Changeset d067d45 for src/boundary.cpp
- Timestamp:
- Jul 23, 2009, 1:45:24 PM (16 years ago)
- Branches:
- Action_Thermostats, Add_AtomRandomPerturbation, Add_FitFragmentPartialChargesAction, Add_RotateAroundBondAction, Add_SelectAtomByNameAction, Added_ParseSaveFragmentResults, AddingActions_SaveParseParticleParameters, Adding_Graph_to_ChangeBondActions, Adding_MD_integration_tests, Adding_ParticleName_to_Atom, Adding_StructOpt_integration_tests, AtomFragments, Automaking_mpqc_open, AutomationFragmentation_failures, Candidate_v1.5.4, Candidate_v1.6.0, Candidate_v1.6.1, 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:
- 51c910
- Parents:
- ce5ac3 (diff), 437922 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)links above to see all the changes relative to each parent. - git-author:
- Frederik Heber <heber@…> (07/23/09 12:34:47)
- git-committer:
- Frederik Heber <heber@…> (07/23/09 13:45:24)
- File:
-
- 1 edited
-
src/boundary.cpp (modified) (27 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/boundary.cpp
rce5ac3 rd067d45 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 ================================= … … 28 31 { 29 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; 30 35 node = NULL; 31 36 lines.clear(); … … 33 38 ; 34 39 35 void 36 BoundaryPointSet::AddLine(class BoundaryLineSet *line) 40 void BoundaryPointSet::AddLine(class BoundaryLineSet *line) 37 41 { 38 42 cout << Verbose(6) << "Adding " << *this << " to line " << *line << "." … … 101 105 cout << Verbose(5) << *endpoints[i] << " has still lines it's attached to." << endl; 102 106 } 107 if (!triangles.empty()) 108 cerr << "WARNING: Memory Leak! I " << *this << " am still connected to some triangles." << endl; 103 109 } 104 110 ; … … 109 115 cout << Verbose(6) << "Add " << triangle->Nr << " to line " << *this << "." 110 116 << endl; 111 triangles.insert(TrianglePair( TrianglesCount, triangle));117 triangles.insert(TrianglePair(triangle->Nr, triangle)); 112 118 TrianglesCount++; 113 119 } … … 205 211 206 212 // make it always point inward (any offset vector onto plane projected onto normal vector suffices) 207 if ( endpoints[0]->node->x.Projection(&OtherVector) > 0)213 if (NormalVector.Projection(&OtherVector) > 0) 208 214 NormalVector.Scale(-1.); 209 215 } … … 565 571 ; 566 572 567 /** Creates the objects in a raster3d file (renderable with a header.r3d)573 /** Creates the objects in a VRML file. 568 574 * \param *out output stream for debugging 569 * \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 570 630 * \param *Tess Tesselation structure with constructed triangles 571 631 * \param *mol molecule structure with atom positions … … 603 663 604 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"; 605 666 for (TriangleMap::iterator TriangleRunner = Tess->TrianglesOnBoundary.begin(); TriangleRunner != Tess->TrianglesOnBoundary.end(); TriangleRunner++) { 606 667 *rasterfile << "1" << endl << " "; // 1 is triangle type … … 613 674 *rasterfile << "18" << endl << " 0.5 0.5 0.5" << endl; // 18 is transparency type for previous object 614 675 } 676 *rasterfile << "9\n terminating special property\n"; 615 677 } else { 616 678 cerr << "ERROR: Given rasterfile is " << rasterfile << "." << endl; … … 673 735 * Determines first the convex envelope, then tesselates it and calculates its volume. 674 736 * \param *out output stream for debugging 675 * \param * tecplot output stream for tecplotdata737 * \param *filename filename prefix for output of vertex data 676 738 * \param *configuration needed for path to store convex envelope file 677 739 * \param *BoundaryPoints NDIM set of boundary points on the projected plane per axis, on return if desired … … 680 742 */ 681 743 double 682 VolumeOfConvexEnvelope(ofstream *out, ofstream *tecplot, config *configuration,744 VolumeOfConvexEnvelope(ofstream *out, const char *filename, config *configuration, 683 745 Boundaries *BoundaryPtr, molecule *mol) 684 746 { … … 761 823 y.CopyVector(&runner->second->endpoints[0]->node->x); 762 824 y.SubtractVector(&runner->second->endpoints[2]->node->x); 763 a = sqrt(runner->second->endpoints[0]->node->x.Distance (825 a = sqrt(runner->second->endpoints[0]->node->x.DistanceSquared( 764 826 &runner->second->endpoints[1]->node->x)); 765 b = sqrt(runner->second->endpoints[0]->node->x.Distance (827 b = sqrt(runner->second->endpoints[0]->node->x.DistanceSquared( 766 828 &runner->second->endpoints[2]->node->x)); 767 c = sqrt(runner->second->endpoints[2]->node->x.Distance (829 c = sqrt(runner->second->endpoints[2]->node->x.DistanceSquared( 768 830 &runner->second->endpoints[1]->node->x)); 769 G = sqrt(((a * a + b * b + c * c) * (a * a + b * b + c * c) - 2 * (a * a 770 * a * a + b * b * b * b + c * c * c * c)) / 16.); // area of tesselated triangle 831 G = sqrt(((a + b + c) * (a + b + c) - 2 * (a * a + b * b + c * c)) / 16.); // area of tesselated triangle 771 832 x.MakeNormalVector(&runner->second->endpoints[0]->node->x, 772 833 &runner->second->endpoints[1]->node->x, … … 797 858 798 859 // 8. Store triangles in tecplot file 860 string OutputName(filename); 861 OutputName.append(TecplotSuffix); 862 ofstream *tecplot = new ofstream(OutputName.c_str()); 799 863 write_tecplot_file(out, tecplot, TesselStruct, mol, 0); 864 tecplot->close(); 865 delete(tecplot); 800 866 801 867 // free reference lists … … 998 1064 for (; C != PointsOnBoundary.end(); C++) 999 1065 { 1000 tmp = A->second->node->x.Distance (&B->second->node->x);1066 tmp = A->second->node->x.DistanceSquared(&B->second->node->x); 1001 1067 distance = tmp * tmp; 1002 tmp = A->second->node->x.Distance (&C->second->node->x);1068 tmp = A->second->node->x.DistanceSquared(&C->second->node->x); 1003 1069 distance += tmp * tmp; 1004 tmp = B->second->node->x.Distance (&C->second->node->x);1070 tmp = B->second->node->x.DistanceSquared(&C->second->node->x); 1005 1071 distance += tmp * tmp; 1006 1072 DistanceMMap.insert(DistanceMultiMapPair(distance, pair< … … 1070 1136 } 1071 1137 // 4d. Check whether the point is inside the triangle (check distance to each node 1072 tmp = checker->second->node->x.Distance (&A->second->node->x);1138 tmp = checker->second->node->x.DistanceSquared(&A->second->node->x); 1073 1139 int innerpoint = 0; 1074 if ((tmp < A->second->node->x.Distance (1140 if ((tmp < A->second->node->x.DistanceSquared( 1075 1141 &baseline->second.first->second->node->x)) && (tmp 1076 < A->second->node->x.Distance (1142 < A->second->node->x.DistanceSquared( 1077 1143 &baseline->second.second->second->node->x))) 1078 1144 innerpoint++; 1079 tmp = checker->second->node->x.Distance (1145 tmp = checker->second->node->x.DistanceSquared( 1080 1146 &baseline->second.first->second->node->x); 1081 if ((tmp < baseline->second.first->second->node->x.Distance (1147 if ((tmp < baseline->second.first->second->node->x.DistanceSquared( 1082 1148 &A->second->node->x)) && (tmp 1083 < baseline->second.first->second->node->x.Distance (1149 < baseline->second.first->second->node->x.DistanceSquared( 1084 1150 &baseline->second.second->second->node->x))) 1085 1151 innerpoint++; 1086 tmp = checker->second->node->x.Distance (1152 tmp = checker->second->node->x.DistanceSquared( 1087 1153 &baseline->second.second->second->node->x); 1088 if ((tmp < baseline->second.second->second->node->x.Distance (1154 if ((tmp < baseline->second.second->second->node->x.DistanceSquared( 1089 1155 &baseline->second.first->second->node->x)) && (tmp 1090 < baseline->second.second->second->node->x.Distance (1156 < baseline->second.second->second->node->x.DistanceSquared( 1091 1157 &A->second->node->x))) 1092 1158 innerpoint++; … … 1483 1549 ; 1484 1550 1551 1552 double det_get(gsl_matrix *A, int inPlace) { 1553 /* 1554 inPlace = 1 => A is replaced with the LU decomposed copy. 1555 inPlace = 0 => A is retained, and a copy is used for LU. 1556 */ 1557 1558 double det; 1559 int signum; 1560 gsl_permutation *p = gsl_permutation_alloc(A->size1); 1561 gsl_matrix *tmpA; 1562 1563 if (inPlace) 1564 tmpA = A; 1565 else { 1566 gsl_matrix *tmpA = gsl_matrix_alloc(A->size1, A->size2); 1567 gsl_matrix_memcpy(tmpA , A); 1568 } 1569 1570 1571 gsl_linalg_LU_decomp(tmpA , p , &signum); 1572 det = gsl_linalg_LU_det(tmpA , signum); 1573 gsl_permutation_free(p); 1574 if (! inPlace) 1575 gsl_matrix_free(tmpA); 1576 1577 return det; 1578 }; 1579 1580 void get_sphere(Vector *center, Vector &a, Vector &b, Vector &c, double RADIUS) 1581 { 1582 gsl_matrix *A = gsl_matrix_calloc(3,3); 1583 double m11, m12, m13, m14; 1584 1585 for(int i=0;i<3;i++) { 1586 gsl_matrix_set(A, i, 0, a.x[i]); 1587 gsl_matrix_set(A, i, 1, b.x[i]); 1588 gsl_matrix_set(A, i, 2, c.x[i]); 1589 } 1590 m11 = det_get(A, 1); 1591 1592 for(int i=0;i<3;i++) { 1593 gsl_matrix_set(A, i, 0, a.x[i]*a.x[i] + b.x[i]*b.x[i] + c.x[i]*c.x[i]); 1594 gsl_matrix_set(A, i, 1, b.x[i]); 1595 gsl_matrix_set(A, i, 2, c.x[i]); 1596 } 1597 m12 = det_get(A, 1); 1598 1599 for(int i=0;i<3;i++) { 1600 gsl_matrix_set(A, i, 0, a.x[i]*a.x[i] + b.x[i]*b.x[i] + c.x[i]*c.x[i]); 1601 gsl_matrix_set(A, i, 1, a.x[i]); 1602 gsl_matrix_set(A, i, 2, c.x[i]); 1603 } 1604 m13 = det_get(A, 1); 1605 1606 for(int i=0;i<3;i++) { 1607 gsl_matrix_set(A, i, 0, a.x[i]*a.x[i] + b.x[i]*b.x[i] + c.x[i]*c.x[i]); 1608 gsl_matrix_set(A, i, 1, a.x[i]); 1609 gsl_matrix_set(A, i, 2, b.x[i]); 1610 } 1611 m14 = det_get(A, 1); 1612 1613 if (fabs(m11) < MYEPSILON) 1614 cerr << "ERROR: three points are colinear." << endl; 1615 1616 center->x[0] = 0.5 * m12/ m11; 1617 center->x[1] = -0.5 * m13/ m11; 1618 center->x[2] = 0.5 * m14/ m11; 1619 1620 if (fabs(a.Distance(center) - RADIUS) > MYEPSILON) 1621 cerr << "ERROR: The given center is further way by " << fabs(a.Distance(center) - RADIUS) << " from a than RADIUS." << endl; 1622 1623 gsl_matrix_free(A); 1624 }; 1625 1626 1627 1485 1628 /** 1486 1629 * Function returns center of sphere with RADIUS, which rests on points a, b, c … … 1489 1632 * @param b vector second point of triangle 1490 1633 * @param c vector third point of triangle 1491 * @param *Umkreismittelpunkt new cneter point of circumference1492 1634 * @param Direction vector indicates up/down 1493 1635 * @param AlternativeDirection vecotr, needed in case the triangles have 90 deg angle … … 1500 1642 * @param Umkreisradius double radius of circumscribing circle 1501 1643 */ 1502 1503 void Get_center_of_sphere(Vector* Center, Vector a, Vector b, Vector c, Vector *NewUmkreismittelpunkt, Vector* Direction, Vector* AlternativeDirection, 1504 double HalfplaneIndicator, double AlternativeIndicator, double alpha, double beta, double gamma, double RADIUS, double Umkreisradius) 1505 { 1506 Vector TempNormal, helper; 1507 double Restradius; 1508 cout << Verbose(3) << "Begin of Get_center_of_sphere.\n"; 1509 Center->Zero(); 1510 helper.CopyVector(&a); 1511 helper.Scale(sin(2.*alpha)); 1512 Center->AddVector(&helper); 1513 helper.CopyVector(&b); 1514 helper.Scale(sin(2.*beta)); 1515 Center->AddVector(&helper); 1516 helper.CopyVector(&c); 1517 helper.Scale(sin(2.*gamma)); 1518 Center->AddVector(&helper); 1519 //*Center = a * sin(2.*alpha) + b * sin(2.*beta) + c * sin(2.*gamma) ; 1520 Center->Scale(1./(sin(2.*alpha) + sin(2.*beta) + sin(2.*gamma))); 1521 NewUmkreismittelpunkt->CopyVector(Center); 1522 cout << Verbose(4) << "Center of new circumference is " << *NewUmkreismittelpunkt << ".\n"; 1523 // Here we calculated center of circumscribing circle, using barycentric coordinates 1524 cout << Verbose(4) << "Center of circumference is " << *Center << " in direction " << *Direction << ".\n"; 1525 1526 TempNormal.CopyVector(&a); 1527 TempNormal.SubtractVector(&b); 1528 helper.CopyVector(&a); 1529 helper.SubtractVector(&c); 1530 TempNormal.VectorProduct(&helper); 1531 if (fabs(HalfplaneIndicator) < MYEPSILON) 1532 { 1533 if ((TempNormal.ScalarProduct(AlternativeDirection) <0 and AlternativeIndicator >0) or (TempNormal.ScalarProduct(AlternativeDirection) >0 and AlternativeIndicator <0)) 1534 { 1535 TempNormal.Scale(-1); 1536 } 1537 } 1538 else 1539 { 1540 if (TempNormal.ScalarProduct(Direction)<0 && HalfplaneIndicator >0 || TempNormal.ScalarProduct(Direction)>0 && HalfplaneIndicator<0) 1541 { 1542 TempNormal.Scale(-1); 1543 } 1544 } 1545 1546 TempNormal.Normalize(); 1547 Restradius = sqrt(RADIUS*RADIUS - Umkreisradius*Umkreisradius); 1548 cout << Verbose(4) << "Height of center of circumference to center of sphere is " << Restradius << ".\n"; 1549 TempNormal.Scale(Restradius); 1550 cout << Verbose(4) << "Shift vector to sphere of circumference is " << TempNormal << ".\n"; 1551 1552 Center->AddVector(&TempNormal); 1553 cout << Verbose(4) << "Center of sphere of circumference is " << *Center << ".\n"; 1554 cout << Verbose(3) << "End of Get_center_of_sphere.\n"; 1555 } 1556 ; 1557 1644 void Get_center_of_sphere(Vector* Center, Vector a, Vector b, Vector c, Vector *NewUmkreismittelpunkt, Vector* Direction, Vector* AlternativeDirection, 1645 double HalfplaneIndicator, double AlternativeIndicator, double alpha, double beta, double gamma, double RADIUS, double Umkreisradius) 1646 { 1647 Vector TempNormal, helper; 1648 double Restradius; 1649 Vector OtherCenter; 1650 cout << Verbose(3) << "Begin of Get_center_of_sphere.\n"; 1651 Center->Zero(); 1652 helper.CopyVector(&a); 1653 helper.Scale(sin(2.*alpha)); 1654 Center->AddVector(&helper); 1655 helper.CopyVector(&b); 1656 helper.Scale(sin(2.*beta)); 1657 Center->AddVector(&helper); 1658 helper.CopyVector(&c); 1659 helper.Scale(sin(2.*gamma)); 1660 Center->AddVector(&helper); 1661 //*Center = a * sin(2.*alpha) + b * sin(2.*beta) + c * sin(2.*gamma) ; 1662 Center->Scale(1./(sin(2.*alpha) + sin(2.*beta) + sin(2.*gamma))); 1663 NewUmkreismittelpunkt->CopyVector(Center); 1664 cout << Verbose(4) << "Center of new circumference is " << *NewUmkreismittelpunkt << ".\n"; 1665 // Here we calculated center of circumscribing circle, using barycentric coordinates 1666 cout << Verbose(4) << "Center of circumference is " << *Center << " in direction " << *Direction << ".\n"; 1667 1668 TempNormal.CopyVector(&a); 1669 TempNormal.SubtractVector(&b); 1670 helper.CopyVector(&a); 1671 helper.SubtractVector(&c); 1672 TempNormal.VectorProduct(&helper); 1673 if (fabs(HalfplaneIndicator) < MYEPSILON) 1674 { 1675 if ((TempNormal.ScalarProduct(AlternativeDirection) <0 and AlternativeIndicator >0) or (TempNormal.ScalarProduct(AlternativeDirection) >0 and AlternativeIndicator <0)) 1676 { 1677 TempNormal.Scale(-1); 1678 } 1679 } 1680 else 1681 { 1682 if (TempNormal.ScalarProduct(Direction)<0 && HalfplaneIndicator >0 || TempNormal.ScalarProduct(Direction)>0 && HalfplaneIndicator<0) 1683 { 1684 TempNormal.Scale(-1); 1685 } 1686 } 1687 TempNormal.Normalize(); 1688 Restradius = sqrt(RADIUS*RADIUS - Umkreisradius*Umkreisradius); 1689 cout << Verbose(4) << "Height of center of circumference to center of sphere is " << Restradius << ".\n"; 1690 TempNormal.Scale(Restradius); 1691 cout << Verbose(4) << "Shift vector to sphere of circumference is " << TempNormal << ".\n"; 1692 1693 Center->AddVector(&TempNormal); 1694 cout << Verbose(0) << "Center of sphere of circumference is " << *Center << ".\n"; 1695 get_sphere(&OtherCenter, a, b, c, RADIUS); 1696 cout << Verbose(0) << "OtherCenter of sphere of circumference is " << OtherCenter << ".\n"; 1697 cout << Verbose(3) << "End of Get_center_of_sphere.\n"; 1698 }; 1558 1699 1559 1700 /** This recursive function finds a third point, to form a triangle with two given ones. … … 1580 1721 * @param mol molecule structure with atoms and bonds 1581 1722 */ 1582 1583 1723 void Tesselation::Find_next_suitable_point_via_Angle_of_Sphere(atom* a, atom* b, atom* c, atom* Candidate, atom* Parent, 1584 1724 int RecursionLevel, Vector *Chord, Vector *direction1, Vector *OldNormal, Vector ReferencePoint, … … 1633 1773 } 1634 1774 1635 if ((M_PI* 4. > alpha*5.) && (M_PI*4. > beta*5.) && (M_PI*4 > gamma*5.)) {1775 if ((M_PI*179./180. > alpha) && (M_PI*179./180. > beta) && (M_PI*179./180. > gamma)) { 1636 1776 Umkreisradius = SideA / 2.0 / sin(alpha); 1637 1777 //cout << Umkreisradius << endl; … … 1655 1795 cout << Verbose(3) << "Candidate is in search direction: " << sign << "." << endl; 1656 1796 } 1657 1658 Get_center_of_sphere(&Mittelpunkt, (a->x), (b->x), (Candidate->x), &NewUmkreismittelpunkt, OldNormal, direction1, sign, AlternativeSign, alpha, beta, gamma, RADIUS, Umkreisradius); 1659 1660 AngleCheck.CopyVector(&ReferencePoint); 1661 AngleCheck.Scale(-1); 1662 //cout << "AngleCheck is " << AngleCheck.x[0] << " "<< AngleCheck.x[1] << " "<< AngleCheck.x[2] << " "<< endl; 1663 AngleCheck.AddVector(&Mittelpunkt); 1664 //cout << "AngleCheck is " << AngleCheck.x[0] << " "<< AngleCheck.x[1] << " "<< AngleCheck.x[2] << " "<< endl; 1665 cout << Verbose(4) << "Reference vector to sphere's center is " << AngleCheck << "." << endl; 1666 1667 BallAngle = AngleCheck.Angle(OldNormal); 1668 cout << Verbose(3) << "Angle between normal of base triangle and center of ball sphere is :" << BallAngle << "." << endl; 1669 1670 //cout << "direction1 is " << direction1->x[0] <<" "<< direction1->x[1] <<" "<< direction1->x[2] <<" " << endl; 1671 //cout << "AngleCheck is " << AngleCheck.x[0] << " "<< AngleCheck.x[1] << " "<< AngleCheck.x[2] << " "<< endl; 1797 if (sign >= 0) { 1798 cout << Verbose(3) << "Candidate is in search direction: " << sign << "." << endl; 1799 Get_center_of_sphere(&Mittelpunkt, (a->x), (b->x), (Candidate->x), &NewUmkreismittelpunkt, OldNormal, direction1, sign, AlternativeSign, alpha, beta, gamma, RADIUS, Umkreisradius); 1800 Mittelpunkt.SubtractVector(&ReferencePoint); 1801 cout << Verbose(3) << "Reference vector to sphere's center is " << Mittelpunkt << "." << endl; 1802 BallAngle = Mittelpunkt.Angle(OldNormal); 1803 cout << Verbose(3) << "Angle between normal of base triangle and center of ball sphere is :" << BallAngle << "." << endl; 1804 1672 1805 1673 1806 cout << Verbose(3) << "BallAngle is " << BallAngle << " Sign is " << sign << endl; 1674 1807 1675 NewUmkreismittelpunkt.SubtractVector(&ReferencePoint); 1676 1677 if ((AngleCheck.ScalarProduct(direction1) >=0) || (fabs(NewUmkreismittelpunkt.Norm()) < MYEPSILON)) { 1678 if (Storage[0]< -1.5) { // first Candidate at all 1679 if (1) {//if (CheckPresenceOfTriangle((ofstream *)&cout,a,b,Candidate)) { 1680 cout << Verbose(2) << "First good candidate is " << *Candidate << " with "; 1681 Opt_Candidate = Candidate; 1682 Storage[0] = sign; 1683 Storage[1] = AlternativeSign; 1684 Storage[2] = BallAngle; 1685 cout << " angle " << Storage[2] << " and Up/Down " 1686 << Storage[0] << endl; 1687 } else 1688 cout << "Candidate " << *Candidate << " does not belong to a valid triangle." << endl; 1689 } else { 1690 if ( Storage[2] > BallAngle) { 1691 if (1) { //if (CheckPresenceOfTriangle((ofstream *)&cout,a,b,Candidate)) { 1692 cout << Verbose(2) << "Next better candidate is " << *Candidate << " with "; 1808 if ((Mittelpunkt.ScalarProduct(direction1) >=0) || (fabs(NewUmkreismittelpunkt.Norm()) < MYEPSILON)) { 1809 if (Storage[0]< -1.5) { // first Candidate at all 1810 if (1) {//if (CheckPresenceOfTriangle((ofstream *)&cout,a,b,Candidate)) { 1811 cout << Verbose(2) << "First good candidate is " << *Candidate << " with "; 1693 1812 Opt_Candidate = Candidate; 1694 1813 Storage[0] = sign; 1695 1814 Storage[1] = AlternativeSign; 1696 1815 Storage[2] = BallAngle; 1697 cout << " angle " << Storage[2] << " and Up/Down " 1698 << Storage[0] << endl; 1816 cout << " angle " << Storage[2] << " and Up/Down " << Storage[0] << endl; 1699 1817 } else 1700 1818 cout << "Candidate " << *Candidate << " does not belong to a valid triangle." << endl; 1701 1819 } else { 1702 if (DEBUG) { 1703 cout << Verbose(3) << *Candidate << " looses against better candidate " << *Opt_Candidate << "." << endl; 1820 if ( Storage[2] > BallAngle) { 1821 if (1) { //if (CheckPresenceOfTriangle((ofstream *)&cout,a,b,Candidate)) { 1822 cout << Verbose(2) << "Next better candidate is " << *Candidate << " with "; 1823 Opt_Candidate = Candidate; 1824 Storage[0] = sign; 1825 Storage[1] = AlternativeSign; 1826 Storage[2] = BallAngle; 1827 cout << " angle " << Storage[2] << " and Up/Down " << Storage[0] << endl; 1828 } else 1829 cout << "Candidate " << *Candidate << " does not belong to a valid triangle." << endl; 1830 } else { 1831 if (DEBUG) { 1832 cout << Verbose(3) << *Candidate << " looses against better candidate " << *Opt_Candidate << "." << endl; 1833 } 1704 1834 } 1835 } 1836 } else { 1837 if (DEBUG) { 1838 cout << Verbose(3) << *Candidate << " refused due to Up/Down sign which is " << sign << endl; 1705 1839 } 1706 1840 } 1707 1841 } else { 1708 1842 if (DEBUG) { 1709 cout << Verbose(3) << *Candidate << " refused due to Up/Down sign which is " << sign<< endl;1843 cout << Verbose(3) << *Candidate << " is not in search direction." << endl; 1710 1844 } 1711 1845 } … … 1741 1875 1742 1876 1743 /** This recursive function finds a third point, to form a triangle with two given ones. 1744 * Two atoms are fixed, a candidate is supplied, additionally two vectors for direction distinction, a Storage area to \ 1745 * supply results to the calling function, the radius of the sphere which the triangle shall support and the molecule \ 1746 * upon which we operate. 1747 * If the candidate is more fitting to support the sphere than the already stored atom is, then we write its general \ 1748 * direction and angle into Storage. 1749 * We the determine the recursive level we have reached and if this is not on the threshold yet, call this function again, \ 1750 * with all neighbours of the candidate. 1751 * @param a first point 1752 * @param b second point 1753 * @param Candidate base point along whose bonds to start looking from 1754 * @param Parent point to avoid during search as its wrong direction 1755 * @param RecursionLevel contains current recursion depth 1756 * @param Chord baseline vector of first and second point 1757 * @param d1 second in plane vector (along with \a Chord) of the triangle the baseline belongs to 1758 * @param OldNormal normal of the triangle which the baseline belongs to 1759 * @param Opt_Candidate candidate reference to return 1760 * @param Opt_Mittelpunkt Centerpoint of ball, when resting on Opt_Candidate 1761 * @param Storage array containing two angles of current Opt_Candidate 1762 * @param RADIUS radius of ball 1763 * @param mol molecule structure with atoms and bonds 1764 */ 1765 void Find_next_suitable_point(atom* a, atom* b, atom* Candidate, atom* Parent, 1766 int RecursionLevel, Vector *Chord, Vector *d1, Vector *OldNormal, 1767 atom*& Opt_Candidate, Vector *Opt_Mittelpunkt, double *Storage, const double RADIUS, molecule* mol) 1768 { 1769 /* OldNormal is normal vector on the old triangle 1770 * d1 is normal on the triangle line, from which we come, as well as on OldNormal. 1771 * Chord points from b to a!!! 1772 */ 1773 Vector dif_a; //Vector from a to candidate 1774 Vector dif_b; //Vector from b to candidate 1775 Vector AngleCheck, AngleCheckReference, DirectionCheckPoint; 1776 Vector TempNormal, Umkreismittelpunkt, Mittelpunkt, helper; 1777 1778 double CurrentEpsilon = 0.1; 1779 double alpha, beta, gamma, SideA, SideB, SideC, sign, Umkreisradius, Restradius; 1780 double BallAngle; 1781 atom *Walker; // variable atom point 1782 1783 1784 dif_a.CopyVector(&(a->x)); 1785 dif_a.SubtractVector(&(Candidate->x)); 1786 dif_b.CopyVector(&(b->x)); 1787 dif_b.SubtractVector(&(Candidate->x)); 1788 DirectionCheckPoint.CopyVector(&dif_a); 1789 DirectionCheckPoint.Scale(-1); 1790 DirectionCheckPoint.ProjectOntoPlane(Chord); 1791 1792 SideA = dif_b.Norm(); 1793 SideB = dif_a.Norm(); 1794 SideC = Chord->Norm(); 1795 //Chord->Scale(-1); 1796 1797 alpha = Chord->Angle(&dif_a); 1798 beta = M_PI - Chord->Angle(&dif_b); 1799 gamma = dif_a.Angle(&dif_b); 1800 1801 1802 if (DEBUG) { 1803 cout << "Atom number" << Candidate->nr << endl; 1804 Candidate->x.Output((ofstream *) &cout); 1805 cout << "number of bonds " << mol->NumberOfBondsPerAtom[Candidate->nr] << endl; 1806 } 1807 1808 if (a != Candidate and b != Candidate) { 1809 // alpha = dif_a.Angle(&dif_b) / 2.; 1810 // SideA = Chord->Norm() / 2.;// (Chord->Norm()/2.) / sin(0.5*alpha); 1811 // SideB = dif_a.Norm(); 1812 // centerline = SideA * SideA + SideB * SideB - 2. * SideA * SideB * cos( 1813 // alpha); // note this is squared of center line length 1814 // centerline = (Chord->Norm()/2.) / sin(0.5*alpha); 1815 // Those are remains from Freddie. Needed? 1816 1817 Umkreisradius = SideA / 2.0 / sin(alpha); 1818 //cout << Umkreisradius << endl; 1819 //cout << SideB / 2.0 / sin(beta) << endl; 1820 //cout << SideC / 2.0 / sin(gamma) << endl; 1821 1822 if (Umkreisradius < RADIUS && DirectionCheckPoint.ScalarProduct(&(Candidate->x))>0) { //Checking whether ball will at least rest o points. 1823 // intermediate calculations to aquire centre of sphere, called Mittelpunkt: 1824 Umkreismittelpunkt.Zero(); 1825 helper.CopyVector(&a->x); 1826 helper.Scale(sin(2.*alpha)); 1827 Umkreismittelpunkt.AddVector(&helper); 1828 helper.CopyVector(&b->x); 1829 helper.Scale(sin(2.*beta)); 1830 Umkreismittelpunkt.AddVector(&helper); 1831 helper.CopyVector(&Candidate->x); 1832 helper.Scale(sin(2.*gamma)); 1833 Umkreismittelpunkt.AddVector(&helper); 1834 //Umkreismittelpunkt = (a->x) * sin(2.*alpha) + b->x * sin(2.*beta) + (Candidate->x) * sin(2.*gamma) ; 1835 Umkreismittelpunkt.Scale(1/(sin(2*alpha) + sin(2*beta) + sin(2*gamma))); 1836 1837 TempNormal.CopyVector(&dif_a); 1838 TempNormal.VectorProduct(&dif_b); 1839 if (TempNormal.ScalarProduct(OldNormal)<0 && sign>0 || TempNormal.ScalarProduct(OldNormal)>0 && sign<0) { 1840 TempNormal.Scale(-1); 1877 /** Constructs the center of the circumcircle defined by three points \a *a, \a *b and \a *c. 1878 * \param *Center new center on return 1879 * \param *a first point 1880 * \param *b second point 1881 * \param *c third point 1882 */ 1883 void GetCenterofCircumcircle(Vector *Center, Vector *a, Vector *b, Vector *c) 1884 { 1885 Vector helper; 1886 double alpha, beta, gamma; 1887 Vector SideA, SideB, SideC; 1888 SideA.CopyVector(b); 1889 SideA.SubtractVector(c); 1890 SideB.CopyVector(c); 1891 SideB.SubtractVector(a); 1892 SideC.CopyVector(a); 1893 SideC.SubtractVector(b); 1894 alpha = M_PI - SideB.Angle(&SideC); 1895 beta = M_PI - SideC.Angle(&SideA); 1896 gamma = M_PI - SideA.Angle(&SideB); 1897 cout << Verbose(3) << "INFO: alpha = " << alpha/M_PI*180. << ", beta = " << beta/M_PI*180. << ", gamma = " << gamma/M_PI*180. << "." << endl; 1898 if (fabs(M_PI - alpha - beta - gamma) > HULLEPSILON) 1899 cerr << "Sum of angles " << (alpha+beta+gamma)/M_PI*180. << " > 180 degrees by " << fabs(M_PI - alpha - beta - gamma)/M_PI*180. << "!" << endl; 1900 1901 Center->Zero(); 1902 helper.CopyVector(a); 1903 helper.Scale(sin(2.*alpha)); 1904 Center->AddVector(&helper); 1905 helper.CopyVector(b); 1906 helper.Scale(sin(2.*beta)); 1907 Center->AddVector(&helper); 1908 helper.CopyVector(c); 1909 helper.Scale(sin(2.*gamma)); 1910 Center->AddVector(&helper); 1911 Center->Scale(1./(sin(2.*alpha) + sin(2.*beta) + sin(2.*gamma))); 1912 }; 1913 1914 /** 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. 1915 * Test whether the \a NewSphereCenter is really on the given plane and in distance \a CircleRadius from \a CircleCenter. 1916 * It calculates the angle, making it unique on [0,2.*M_PI) by comparing to SearchDirection. 1917 * 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). 1918 * \param CircleCenter Center of the parameter circle 1919 * \param CirclePlaneNormal normal vector to plane of the parameter circle 1920 * \param CircleRadius radius of the parameter circle 1921 * \param NewSphereCenter new center of a circumcircle 1922 * \param OldSphereCenter old center of a circumcircle, defining the zero "path length" on the parameter circle 1923 * \param NormalVector normal vector 1924 * \param SearchDirection search direction to make angle unique on return. 1925 * \return Angle between \a NewSphereCenter and \a OldSphereCenter relative to \a CircleCenter, 2.*M_PI if one test fails 1926 */ 1927 double GetPathLengthonCircumCircle(Vector &CircleCenter, Vector &CirclePlaneNormal, double CircleRadius, Vector &NewSphereCenter, Vector &OldSphereCenter, Vector &NormalVector, Vector &SearchDirection) 1928 { 1929 Vector helper; 1930 double radius, alpha; 1931 1932 helper.CopyVector(&NewSphereCenter); 1933 // test whether new center is on the parameter circle's plane 1934 if (fabs(helper.ScalarProduct(&CirclePlaneNormal)) > HULLEPSILON) { 1935 cerr << "ERROR: Something's very wrong here: NewSphereCenter is not on the band's plane as desired by " <<fabs(helper.ScalarProduct(&CirclePlaneNormal)) << "!" << endl; 1936 helper.ProjectOntoPlane(&CirclePlaneNormal); 1937 } 1938 radius = helper.ScalarProduct(&helper); 1939 // test whether the new center vector has length of CircleRadius 1940 if (fabs(radius - CircleRadius) > HULLEPSILON) 1941 cerr << Verbose(1) << "ERROR: The projected center of the new sphere has radius " << radius << " instead of " << CircleRadius << "." << endl; 1942 alpha = helper.Angle(&OldSphereCenter); 1943 // make the angle unique by checking the halfplanes/search direction 1944 if (helper.ScalarProduct(&SearchDirection) < -HULLEPSILON) // acos is not unique on [0, 2.*M_PI), hence extra check to decide between two half intervals 1945 alpha = 2.*M_PI - alpha; 1946 cout << Verbose(2) << "INFO: RelativeNewSphereCenter is " << helper << ", RelativeOldSphereCenter is " << OldSphereCenter << " and resulting angle is " << alpha << "." << endl; 1947 radius = helper.Distance(&OldSphereCenter); 1948 helper.ProjectOntoPlane(&NormalVector); 1949 // check whether new center is somewhat away or at least right over the current baseline to prevent intersecting triangles 1950 if ((radius > HULLEPSILON) || (helper.Norm() < HULLEPSILON)) { 1951 cout << Verbose(2) << "INFO: Distance between old and new center is " << radius << " and between new center and baseline center is " << helper.Norm() << "." << endl; 1952 return alpha; 1953 } else { 1954 cout << Verbose(1) << "ERROR: NewSphereCenter " << helper << " is too close to OldSphereCenter" << OldSphereCenter << "." << endl; 1955 return 2.*M_PI; 1956 } 1957 }; 1958 1959 1960 /** This recursive function finds a third point, to form a triangle with two given ones. 1961 * The idea is as follows: A sphere with fixed radius is (almost) uniquely defined in space by three points 1962 * that sit on its boundary. Hence, when two points are given and we look for the (next) third point, then 1963 * the center of the sphere is still fixed up to a single parameter. The band of possible values 1964 * describes a circle in 3D-space. The old center of the sphere for the current base triangle gives 1965 * us the "null" on this circle, the new center of the candidate point will be some way along this 1966 * circle. The shorter the way the better is the candidate. Note that the direction is clearly given 1967 * by the normal vector of the base triangle that always points outwards by construction. 1968 * Hence, we construct a Center of this circle which sits right in the middle of the current base line. 1969 * We construct the normal vector that defines the plane this circle lies in, it is just in the 1970 * direction of the baseline. And finally, we need the radius of the circle, which is given by the rest 1971 * with respect to the length of the baseline and the sphere's fixed \a RADIUS. 1972 * Note that there is one difficulty: The circumcircle is uniquely defined, but for the circumsphere's center 1973 * there are two possibilities which becomes clear from the construction as seen below. Hence, we must check 1974 * both. 1975 * Note also that the acos() function is not unique on [0, 2.*M_PI). Hence, we need an additional check 1976 * to decide for one of the two possible angles. Therefore we need a SearchDirection and to make this check 1977 * sensible we need OldSphereCenter to be orthogonal to it. Either we construct SearchDirection orthogonal 1978 * right away, or -- what we do here -- we rotate the relative sphere centers such that this orthogonality 1979 * holds. Then, the normalized projection onto the SearchDirection is either +1 or -1 and thus states whether 1980 * the angle is uniquely in either (0,M_PI] or [M_PI, 2.*M_PI). 1981 * @param BaseTriangle BoundaryTriangleSet of the current base triangle with all three points 1982 * @param BaseLine BoundaryLineSet of BaseTriangle with the current base line 1983 * @param OptCandidate candidate reference on return 1984 * @param OptCandidateCenter candidate's sphere center on return 1985 * @param ShortestAngle the current path length on this circle band for the current Opt_Candidate 1986 * @param RADIUS radius of sphere 1987 * @param *LC LinkedCell structure with neighbouring atoms 1988 */ 1989 // void Find_next_suitable_point(class BoundaryTriangleSet *BaseTriangle, class BoundaryLineSet *BaseLine, atom*& OptCandidate, Vector *OptCandidateCenter, double *ShortestAngle, const double RADIUS, LinkedCell *LC) 1990 // { 1991 // atom *Walker = NULL; 1992 // Vector CircleCenter; // center of the circle, i.e. of the band of sphere's centers 1993 // Vector CirclePlaneNormal; // normal vector defining the plane this circle lives in 1994 // Vector OldSphereCenter; // center of the sphere defined by the three points of BaseTriangle 1995 // Vector NewSphereCenter; // center of the sphere defined by the two points of BaseLine and the one of Candidate, first possibility 1996 // Vector OtherNewSphereCenter; // center of the sphere defined by the two points of BaseLine and the one of Candidate, second possibility 1997 // Vector NewNormalVector; // normal vector of the Candidate's triangle 1998 // Vector SearchDirection; // vector that points out of BaseTriangle and is orthonormal to its NormalVector (i.e. the desired direction for the best Candidate) 1999 // Vector helper; 2000 // LinkedAtoms *List = NULL; 2001 // double CircleRadius; // radius of this circle 2002 // double radius; 2003 // double alpha, Otheralpha; // angles (i.e. parameter for the circle). 2004 // double Nullalpha; // angle between OldSphereCenter and NormalVector of base triangle 2005 // int N[NDIM], Nlower[NDIM], Nupper[NDIM]; 2006 // atom *Candidate = NULL; 2007 // 2008 // cout << Verbose(1) << "Begin of Find_next_suitable_point" << endl; 2009 // 2010 // cout << Verbose(2) << "INFO: NormalVector of BaseTriangle is " << BaseTriangle->NormalVector << "." << endl; 2011 // 2012 // // construct center of circle 2013 // CircleCenter.CopyVector(&(BaseLine->endpoints[0]->node->x)); 2014 // CircleCenter.AddVector(&BaseLine->endpoints[1]->node->x); 2015 // CircleCenter.Scale(0.5); 2016 // 2017 // // construct normal vector of circle 2018 // CirclePlaneNormal.CopyVector(&BaseLine->endpoints[0]->node->x); 2019 // CirclePlaneNormal.SubtractVector(&BaseLine->endpoints[1]->node->x); 2020 // 2021 // // calculate squared radius of circle 2022 // radius = CirclePlaneNormal.ScalarProduct(&CirclePlaneNormal); 2023 // if (radius/4. < RADIUS*RADIUS) { 2024 // CircleRadius = RADIUS*RADIUS - radius/4.; 2025 // CirclePlaneNormal.Normalize(); 2026 // cout << Verbose(2) << "INFO: CircleCenter is at " << CircleCenter << ", CirclePlaneNormal is " << CirclePlaneNormal << " with circle radius " << sqrt(CircleRadius) << "." << endl; 2027 // 2028 // // construct old center 2029 // GetCenterofCircumcircle(&OldSphereCenter, &(BaseTriangle->endpoints[0]->node->x), &(BaseTriangle->endpoints[1]->node->x), &(BaseTriangle->endpoints[2]->node->x)); 2030 // helper.CopyVector(&BaseTriangle->NormalVector); // normal vector ensures that this is correct center of the two possible ones 2031 // radius = BaseLine->endpoints[0]->node->x.DistanceSquared(&OldSphereCenter); 2032 // helper.Scale(sqrt(RADIUS*RADIUS - radius)); 2033 // OldSphereCenter.AddVector(&helper); 2034 // OldSphereCenter.SubtractVector(&CircleCenter); 2035 // cout << Verbose(2) << "INFO: OldSphereCenter is at " << OldSphereCenter << "." << endl; 2036 // 2037 // // test whether old center is on the band's plane 2038 // if (fabs(OldSphereCenter.ScalarProduct(&CirclePlaneNormal)) > HULLEPSILON) { 2039 // cerr << "ERROR: Something's very wrong here: OldSphereCenter is not on the band's plane as desired by " << fabs(OldSphereCenter.ScalarProduct(&CirclePlaneNormal)) << "!" << endl; 2040 // OldSphereCenter.ProjectOntoPlane(&CirclePlaneNormal); 2041 // } 2042 // radius = OldSphereCenter.ScalarProduct(&OldSphereCenter); 2043 // if (fabs(radius - CircleRadius) < HULLEPSILON) { 2044 // 2045 // // construct SearchDirection 2046 // SearchDirection.MakeNormalVector(&BaseTriangle->NormalVector, &CirclePlaneNormal); 2047 // helper.CopyVector(&BaseLine->endpoints[0]->node->x); 2048 // for(int i=0;i<3;i++) // just take next different endpoint 2049 // if ((BaseTriangle->endpoints[i]->node != BaseLine->endpoints[0]->node) && (BaseTriangle->endpoints[i]->node != BaseLine->endpoints[1]->node)) { 2050 // helper.SubtractVector(&BaseTriangle->endpoints[i]->node->x); 2051 // } 2052 // if (helper.ScalarProduct(&SearchDirection) < -HULLEPSILON) // ohoh, SearchDirection points inwards! 2053 // SearchDirection.Scale(-1.); 2054 // SearchDirection.ProjectOntoPlane(&OldSphereCenter); 2055 // SearchDirection.Normalize(); 2056 // cout << Verbose(2) << "INFO: SearchDirection is " << SearchDirection << "." << endl; 2057 // if (fabs(OldSphereCenter.ScalarProduct(&SearchDirection)) > HULLEPSILON) { // rotated the wrong way! 2058 // cerr << "ERROR: SearchDirection and RelativeOldSphereCenter are still not orthogonal!" << endl; 2059 // } 2060 // 2061 // if (LC->SetIndexToVector(&CircleCenter)) { // get cell for the starting atom 2062 // for(int i=0;i<NDIM;i++) // store indices of this cell 2063 // N[i] = LC->n[i]; 2064 // cout << Verbose(2) << "INFO: Center cell is " << N[0] << ", " << N[1] << ", " << N[2] << " with No. " << LC->index << "." << endl; 2065 // } else { 2066 // cerr << "ERROR: Vector " << CircleCenter << " is outside of LinkedCell's bounding box." << endl; 2067 // return; 2068 // } 2069 // // then go through the current and all neighbouring cells and check the contained atoms for possible candidates 2070 // cout << Verbose(2) << "LC Intervals:"; 2071 // for (int i=0;i<NDIM;i++) { 2072 // Nlower[i] = ((N[i]-1) >= 0) ? N[i]-1 : 0; 2073 // Nupper[i] = ((N[i]+1) < LC->N[i]) ? N[i]+1 : LC->N[i]-1; 2074 // cout << " [" << Nlower[i] << "," << Nupper[i] << "] "; 2075 // } 2076 // cout << endl; 2077 // for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++) 2078 // for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++) 2079 // for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) { 2080 // List = LC->GetCurrentCell(); 2081 // cout << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << "." << endl; 2082 // if (List != NULL) { 2083 // for (LinkedAtoms::iterator Runner = List->begin(); Runner != List->end(); Runner++) { 2084 // Candidate = (*Runner); 2085 // 2086 // // check for three unique points 2087 // if ((Candidate != BaseTriangle->endpoints[0]->node) && (Candidate != BaseTriangle->endpoints[1]->node) && (Candidate != BaseTriangle->endpoints[2]->node)) { 2088 // cout << Verbose(1) << "INFO: Current Candidate is " << *Candidate << " at " << Candidate->x << "." << endl; 2089 // 2090 // // construct both new centers 2091 // GetCenterofCircumcircle(&NewSphereCenter, &(BaseLine->endpoints[0]->node->x), &(BaseLine->endpoints[1]->node->x), &(Candidate->x)); 2092 // OtherNewSphereCenter.CopyVector(&NewSphereCenter); 2093 // 2094 // if ((NewNormalVector.MakeNormalVector(&(BaseLine->endpoints[0]->node->x), &(BaseLine->endpoints[1]->node->x), &(Candidate->x))) && (fabs(NewNormalVector.ScalarProduct(&NewNormalVector)) > HULLEPSILON)) { 2095 // helper.CopyVector(&NewNormalVector); 2096 // cout << Verbose(2) << "INFO: NewNormalVector is " << NewNormalVector << "." << endl; 2097 // radius = BaseLine->endpoints[0]->node->x.DistanceSquared(&NewSphereCenter); 2098 // if (radius < RADIUS*RADIUS) { 2099 // helper.Scale(sqrt(RADIUS*RADIUS - radius)); 2100 // cout << Verbose(3) << "INFO: Distance of NewCircleCenter to NewSphereCenter is " << helper.Norm() << "." << endl; 2101 // NewSphereCenter.AddVector(&helper); 2102 // NewSphereCenter.SubtractVector(&CircleCenter); 2103 // cout << Verbose(2) << "INFO: NewSphereCenter is at " << NewSphereCenter << "." << endl; 2104 // 2105 // helper.Scale(-1.); // OtherNewSphereCenter is created by the same vector just in the other direction 2106 // OtherNewSphereCenter.AddVector(&helper); 2107 // OtherNewSphereCenter.SubtractVector(&CircleCenter); 2108 // cout << Verbose(2) << "INFO: OtherNewSphereCenter is at " << OtherNewSphereCenter << "." << endl; 2109 // 2110 // // check both possible centers 2111 // alpha = GetPathLengthonCircumCircle(CircleCenter, CirclePlaneNormal, CircleRadius, NewSphereCenter, OldSphereCenter, BaseTriangle->NormalVector, SearchDirection); 2112 // Otheralpha = GetPathLengthonCircumCircle(CircleCenter, CirclePlaneNormal, CircleRadius, OtherNewSphereCenter, OldSphereCenter, BaseTriangle->NormalVector, SearchDirection); 2113 // alpha = min(alpha, Otheralpha); 2114 // if (*ShortestAngle > alpha) { 2115 // OptCandidate = Candidate; 2116 // *ShortestAngle = alpha; 2117 // if (alpha != Otheralpha) 2118 // OptCandidateCenter->CopyVector(&NewSphereCenter); 2119 // else 2120 // OptCandidateCenter->CopyVector(&OtherNewSphereCenter); 2121 // cout << Verbose(1) << "We have found a better candidate: " << *OptCandidate << " with " << alpha << " and circumsphere's center at " << *OptCandidateCenter << "." << endl; 2122 // } else { 2123 // if (OptCandidate != NULL) 2124 // cout << Verbose(1) << "REJECT: Old candidate: " << *OptCandidate << " is better than " << alpha << " with " << *ShortestAngle << "." << endl; 2125 // else 2126 // cout << Verbose(2) << "REJECT: Candidate " << *Candidate << " with " << alpha << " was rejected." << endl; 2127 // } 2128 // 2129 // } else { 2130 // cout << Verbose(1) << "REJECT: NewSphereCenter " << NewSphereCenter << " is too far away: " << radius << "." << endl; 2131 // } 2132 // } else { 2133 // cout << Verbose(1) << "REJECT: Three points from " << *BaseLine << " and Candidate " << *Candidate << " are linear-dependent." << endl; 2134 // } 2135 // } else { 2136 // cout << Verbose(1) << "REJECT: Base triangle " << *BaseTriangle << " contains Candidate " << *Candidate << "." << endl; 2137 // } 2138 // } 2139 // } 2140 // } 2141 // } else { 2142 // cerr << Verbose(1) << "ERROR: The projected center of the old sphere has radius " << radius << " instead of " << CircleRadius << "." << endl; 2143 // } 2144 // } else { 2145 // cout << Verbose(1) << "Circumcircle for base line " << *BaseLine << " and base triangle " << *BaseTriangle << " is too big!" << endl; 2146 // } 2147 // 2148 // cout << Verbose(1) << "End of Find_next_suitable_point" << endl; 2149 // }; 2150 2151 2152 /** This recursive function finds a third point, to form a triangle with two given ones. 2153 * Note that this function is for the starting triangle. 2154 * The idea is as follows: A sphere with fixed radius is (almost) uniquely defined in space by three points 2155 * that sit on its boundary. Hence, when two points are given and we look for the (next) third point, then 2156 * the center of the sphere is still fixed up to a single parameter. The band of possible values 2157 * describes a circle in 3D-space. The old center of the sphere for the current base triangle gives 2158 * us the "null" on this circle, the new center of the candidate point will be some way along this 2159 * circle. The shorter the way the better is the candidate. Note that the direction is clearly given 2160 * by the normal vector of the base triangle that always points outwards by construction. 2161 * Hence, we construct a Center of this circle which sits right in the middle of the current base line. 2162 * We construct the normal vector that defines the plane this circle lies in, it is just in the 2163 * direction of the baseline. And finally, we need the radius of the circle, which is given by the rest 2164 * with respect to the length of the baseline and the sphere's fixed \a RADIUS. 2165 * Note that there is one difficulty: The circumcircle is uniquely defined, but for the circumsphere's center 2166 * there are two possibilities which becomes clear from the construction as seen below. Hence, we must check 2167 * both. 2168 * Note also that the acos() function is not unique on [0, 2.*M_PI). Hence, we need an additional check 2169 * to decide for one of the two possible angles. Therefore we need a SearchDirection and to make this check 2170 * sensible we need OldSphereCenter to be orthogonal to it. Either we construct SearchDirection orthogonal 2171 * right away, or -- what we do here -- we rotate the relative sphere centers such that this orthogonality 2172 * holds. Then, the normalized projection onto the SearchDirection is either +1 or -1 and thus states whether 2173 * the angle is uniquely in either (0,M_PI] or [M_PI, 2.*M_PI). 2174 * @param NormalVector normal direction of the base triangle (here the unit axis vector, \sa Find_starting_triangle()) 2175 * @param SearchDirection general direction where to search for the next point, relative to center of BaseLine 2176 * @param OldSphereCenter center of sphere for base triangle, relative to center of BaseLine, giving null angle for the parameter circle 2177 * @param BaseLine BoundaryLineSet with the current base line 2178 * @param ThirdNode third atom to avoid in search 2179 * @param OptCandidate candidate reference on return 2180 * @param OptCandidateCenter candidate's sphere center on return 2181 * @param ShortestAngle the current path length on this circle band for the current Opt_Candidate 2182 * @param RADIUS radius of sphere 2183 * @param *LC LinkedCell structure with neighbouring atoms 2184 */ 2185 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) 2186 { 2187 Vector CircleCenter; // center of the circle, i.e. of the band of sphere's centers 2188 Vector CirclePlaneNormal; // normal vector defining the plane this circle lives in 2189 Vector NewSphereCenter; // center of the sphere defined by the two points of BaseLine and the one of Candidate, first possibility 2190 Vector OtherNewSphereCenter; // center of the sphere defined by the two points of BaseLine and the one of Candidate, second possibility 2191 Vector NewNormalVector; // normal vector of the Candidate's triangle 2192 Vector helper; 2193 LinkedAtoms *List = NULL; 2194 double CircleRadius; // radius of this circle 2195 double radius; 2196 double alpha, Otheralpha; // angles (i.e. parameter for the circle). 2197 int N[NDIM], Nlower[NDIM], Nupper[NDIM]; 2198 atom *Candidate = NULL; 2199 2200 cout << Verbose(1) << "Begin of Find_third_point_for_Tesselation" << endl; 2201 2202 cout << Verbose(2) << "INFO: NormalVector of BaseTriangle is " << NormalVector << "." << endl; 2203 2204 // construct center of circle 2205 CircleCenter.CopyVector(&(BaseLine->endpoints[0]->node->x)); 2206 CircleCenter.AddVector(&BaseLine->endpoints[1]->node->x); 2207 CircleCenter.Scale(0.5); 2208 2209 // construct normal vector of circle 2210 CirclePlaneNormal.CopyVector(&BaseLine->endpoints[0]->node->x); 2211 CirclePlaneNormal.SubtractVector(&BaseLine->endpoints[1]->node->x); 2212 2213 // calculate squared radius of circle 2214 radius = CirclePlaneNormal.ScalarProduct(&CirclePlaneNormal); 2215 if (radius/4. < RADIUS*RADIUS) { 2216 CircleRadius = RADIUS*RADIUS - radius/4.; 2217 CirclePlaneNormal.Normalize(); 2218 cout << Verbose(2) << "INFO: CircleCenter is at " << CircleCenter << ", CirclePlaneNormal is " << CirclePlaneNormal << " with circle radius " << sqrt(CircleRadius) << "." << endl; 2219 2220 // test whether old center is on the band's plane 2221 if (fabs(OldSphereCenter.ScalarProduct(&CirclePlaneNormal)) > HULLEPSILON) { 2222 cerr << "ERROR: Something's very wrong here: OldSphereCenter is not on the band's plane as desired by " << fabs(OldSphereCenter.ScalarProduct(&CirclePlaneNormal)) << "!" << endl; 2223 OldSphereCenter.ProjectOntoPlane(&CirclePlaneNormal); 2224 } 2225 radius = OldSphereCenter.ScalarProduct(&OldSphereCenter); 2226 if (fabs(radius - CircleRadius) < HULLEPSILON) { 2227 2228 // check SearchDirection 2229 cout << Verbose(2) << "INFO: SearchDirection is " << SearchDirection << "." << endl; 2230 if (fabs(OldSphereCenter.ScalarProduct(&SearchDirection)) > HULLEPSILON) { // rotated the wrong way! 2231 cerr << "ERROR: SearchDirection and RelativeOldSphereCenter are not orthogonal!" << endl; 1841 2232 } 1842 TempNormal.Normalize(); 1843 Restradius = sqrt(RADIUS*RADIUS - Umkreisradius*Umkreisradius); 1844 TempNormal.Scale(Restradius); 1845 1846 Mittelpunkt.CopyVector(&Umkreismittelpunkt); 1847 Mittelpunkt.AddVector(&TempNormal); //this is center of sphere supported by a, b and Candidate 1848 1849 AngleCheck.CopyVector(Chord); 1850 AngleCheck.Scale(-0.5); 1851 AngleCheck.SubtractVector(&(b->x)); 1852 AngleCheckReference.CopyVector(&AngleCheck); 1853 AngleCheckReference.AddVector(Opt_Mittelpunkt); 1854 AngleCheck.AddVector(&Mittelpunkt); 1855 1856 BallAngle = AngleCheck.Angle(&AngleCheckReference); 1857 1858 d1->ProjectOntoPlane(&AngleCheckReference); 1859 sign = AngleCheck.ScalarProduct(d1); 1860 if (fabs(sign) < MYEPSILON) 1861 sign = 0; 1862 else 1863 sign /= fabs(sign); // +1 if in direction of triangle plane, -1 if in other direction... 1864 1865 1866 if (Storage[0]< -1.5) { // first Candidate at all 1867 cout << "Next better candidate is " << *Candidate << " with "; 1868 Opt_Candidate = Candidate; 1869 Storage[0] = sign; 1870 Storage[1] = BallAngle; 1871 Opt_Mittelpunkt->CopyVector(&Mittelpunkt); 1872 cout << "Angle is " << Storage[1] << ", Halbraum ist " << Storage[0] << endl; 2233 // get cell for the starting atom 2234 if (LC->SetIndexToVector(&CircleCenter)) { 2235 for(int i=0;i<NDIM;i++) // store indices of this cell 2236 N[i] = LC->n[i]; 2237 cout << Verbose(2) << "INFO: Center cell is " << N[0] << ", " << N[1] << ", " << N[2] << " with No. " << LC->index << "." << endl; 1873 2238 } else { 1874 /* 1875 * removed due to change in criterium, now checking angle of ball to old normal. 1876 //We will now check for non interference, that is if the new candidate would have the Opt_Candidate 1877 //within the ball. 1878 1879 Distance = Opt_Candidate->x.Distance(&Mittelpunkt); 1880 //cout << "Opt_Candidate " << Opt_Candidate << " has distance " << Distance << " to Center of Candidate " << endl; 1881 1882 1883 if (Distance >RADIUS) { // We have no interference and may now check whether the new point is better. 1884 */ 1885 //cout << "Atom " << Candidate << " has distance " << Candidate->x.Distance(Opt_Mittelpunkt) << " to Center of Candidate " << endl; 1886 1887 if (((Storage[0] < 0 && fabs(sign - Storage[0]) > CurrentEpsilon))) { //This will give absolute preference to those in "right-hand" quadrants 1888 //(Candidate->x.Distance(Opt_Mittelpunkt) < RADIUS)) //and those where Candidate would be within old Sphere. 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 " << Storage[0] << endl; 1895 } else { 1896 if ((fabs(sign - Storage[0]) < CurrentEpsilon && sign > 0 && Storage[1] > BallAngle) || (fabs(sign - Storage[0]) < CurrentEpsilon && sign < 0 && Storage[1] < BallAngle)) { 1897 //Depending on quadrant we prefer higher or lower atom with respect to Triangle normal first. 1898 cout << "Next better candidate is " << *Candidate << " with "; 1899 Opt_Candidate = Candidate; 1900 Storage[0] = sign; 1901 Storage[1] = BallAngle; 1902 Opt_Mittelpunkt->CopyVector(&Mittelpunkt); 1903 cout << "Angle is " << Storage[1] << ", Halbraum ist " << Storage[0] << endl; 2239 cerr << "ERROR: Vector " << CircleCenter << " is outside of LinkedCell's bounding box." << endl; 2240 return; 2241 } 2242 // then go through the current and all neighbouring cells and check the contained atoms for possible candidates 2243 cout << Verbose(2) << "LC Intervals:"; 2244 for (int i=0;i<NDIM;i++) { 2245 Nlower[i] = ((N[i]-1) >= 0) ? N[i]-1 : 0; 2246 Nupper[i] = ((N[i]+1) < LC->N[i]) ? N[i]+1 : LC->N[i]-1; 2247 cout << " [" << Nlower[i] << "," << Nupper[i] << "] "; 2248 } 2249 cout << endl; 2250 for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++) 2251 for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++) 2252 for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) { 2253 List = LC->GetCurrentCell(); 2254 //cout << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << "." << endl; 2255 if (List != NULL) { 2256 for (LinkedAtoms::iterator Runner = List->begin(); Runner != List->end(); Runner++) { 2257 Candidate = (*Runner); 2258 2259 // check for three unique points 2260 if ((Candidate != BaseLine->endpoints[0]->node) && (Candidate != BaseLine->endpoints[1]->node) && (Candidate != ThirdNode)) { 2261 cout << Verbose(1) << "INFO: Current Candidate is " << *Candidate << " at " << Candidate->x << "." << endl; 2262 2263 // construct both new centers 2264 GetCenterofCircumcircle(&NewSphereCenter, &(BaseLine->endpoints[0]->node->x), &(BaseLine->endpoints[1]->node->x), &(Candidate->x)); 2265 OtherNewSphereCenter.CopyVector(&NewSphereCenter); 2266 2267 if ((NewNormalVector.MakeNormalVector(&(BaseLine->endpoints[0]->node->x), &(BaseLine->endpoints[1]->node->x), &(Candidate->x))) && (fabs(NewNormalVector.ScalarProduct(&NewNormalVector)) > HULLEPSILON)) { 2268 helper.CopyVector(&NewNormalVector); 2269 cout << Verbose(2) << "INFO: NewNormalVector is " << NewNormalVector << "." << endl; 2270 radius = BaseLine->endpoints[0]->node->x.DistanceSquared(&NewSphereCenter); 2271 if (radius < RADIUS*RADIUS) { 2272 helper.Scale(sqrt(RADIUS*RADIUS - radius)); 2273 cout << Verbose(3) << "INFO: Distance of NewCircleCenter to NewSphereCenter is " << helper.Norm() << "." << endl; 2274 NewSphereCenter.AddVector(&helper); 2275 NewSphereCenter.SubtractVector(&CircleCenter); 2276 cout << Verbose(2) << "INFO: NewSphereCenter is at " << NewSphereCenter << "." << endl; 2277 2278 helper.Scale(-1.); // OtherNewSphereCenter is created by the same vector just in the other direction 2279 OtherNewSphereCenter.AddVector(&helper); 2280 OtherNewSphereCenter.SubtractVector(&CircleCenter); 2281 cout << Verbose(2) << "INFO: OtherNewSphereCenter is at " << OtherNewSphereCenter << "." << endl; 2282 2283 // check both possible centers 2284 alpha = GetPathLengthonCircumCircle(CircleCenter, CirclePlaneNormal, CircleRadius, NewSphereCenter, OldSphereCenter, NormalVector, SearchDirection); 2285 Otheralpha = GetPathLengthonCircumCircle(CircleCenter, CirclePlaneNormal, CircleRadius, OtherNewSphereCenter, OldSphereCenter, NormalVector, SearchDirection); 2286 alpha = min(alpha, Otheralpha); 2287 if (*ShortestAngle > alpha) { 2288 OptCandidate = Candidate; 2289 *ShortestAngle = alpha; 2290 if (alpha != Otheralpha) 2291 OptCandidateCenter->CopyVector(&NewSphereCenter); 2292 else 2293 OptCandidateCenter->CopyVector(&OtherNewSphereCenter); 2294 cout << Verbose(1) << "ACCEPT: We have found a better candidate: " << *OptCandidate << " with " << alpha << " and circumsphere's center at " << *OptCandidateCenter << "." << endl; 2295 } else { 2296 if (OptCandidate != NULL) 2297 cout << Verbose(1) << "REJECT: Old candidate: " << *OptCandidate << " is better than " << alpha << " with " << *ShortestAngle << "." << endl; 2298 else 2299 cout << Verbose(2) << "REJECT: Candidate " << *Candidate << " with " << alpha << " was rejected." << endl; 2300 } 2301 2302 } else { 2303 cout << Verbose(1) << "REJECT: NewSphereCenter " << NewSphereCenter << " is too far away: " << radius << "." << endl; 2304 } 2305 } else { 2306 cout << Verbose(1) << "REJECT: Three points from " << *BaseLine << " and Candidate " << *Candidate << " are linear-dependent." << endl; 2307 } 2308 } else { 2309 if (ThirdNode != NULL) 2310 cout << Verbose(1) << "REJECT: Base triangle " << *BaseLine << " and " << *ThirdNode << " contains Candidate " << *Candidate << "." << endl; 2311 else 2312 cout << Verbose(1) << "REJECT: Base triangle " << *BaseLine << " contains Candidate " << *Candidate << "." << endl; 2313 } 2314 } 2315 } 1904 2316 } 1905 }1906 }1907 /*1908 * This is for checking point-angle and presence of Candidates in Ball, currently we are checking the ball Angle.1909 *1910 else1911 {1912 if (sign>0 && BallAngle>0 && Storage[0]<0)1913 {1914 cout << "Next better candidate is " << *Candidate << " with ";1915 Opt_Candidate = Candidate;1916 Storage[0] = sign;1917 Storage[1] = BallAngle;1918 Opt_Mittelpunkt->CopyVector(&Mittelpunkt);1919 cout << "Angle is " << Storage[1] << ", Halbraum ist "1920 << Storage[0] << endl;1921 1922 //Debugging purposes only1923 cout << "Umkreismittelpunkt has coordinates" << Umkreismittelpunkt.x[0] << " "<< Umkreismittelpunkt.x[1] <<" "<<Umkreismittelpunkt.x[2] << endl;1924 cout << "Candidate has coordinates" << Candidate->x.x[0]<< " " << Candidate->x.x[1] << " " << Candidate->x.x[2] << endl;1925 cout << "a has coordinates" << a->x.x[0]<< " " << a->x.x[1] << " " << a->x.x[2] << endl;1926 cout << "b has coordinates" << b->x.x[0]<< " " << b->x.x[1] << " " << b->x.x[2] << endl;1927 cout << "Mittelpunkt has coordinates" << Mittelpunkt.x[0] << " " << Mittelpunkt.x[1]<< " " <<Mittelpunkt.x[2] << endl;1928 cout << "Umkreisradius ist " << Umkreisradius << endl;1929 cout << "Restradius ist " << Restradius << endl;1930 cout << "TempNormal has coordinates " << TempNormal.x[0] << " " << TempNormal.x[1] << " " << TempNormal.x[2] << " " << endl;1931 cout << "OldNormal has coordinates " << OldNormal->x[0] << " " << OldNormal->x[1] << " " << OldNormal->x[2] << " " << endl;1932 cout << "Dist a to UmkreisMittelpunkt " << a->x.Distance(&Umkreismittelpunkt) << endl;1933 cout << "Dist b to UmkreisMittelpunkt " << b->x.Distance(&Umkreismittelpunkt) << endl;1934 cout << "Dist Candidate to UmkreisMittelpunkt " << Candidate->x.Distance(&Umkreismittelpunkt) << endl;1935 cout << "Dist a to Mittelpunkt " << a->x.Distance(&Mittelpunkt) << endl;1936 cout << "Dist b to Mittelpunkt " << b->x.Distance(&Mittelpunkt) << endl;1937 cout << "Dist Candidate to Mittelpunkt " << Candidate->x.Distance(&Mittelpunkt) << endl;1938 1939 1940 1941 }1942 else1943 {1944 if (DEBUG)1945 cout << "Looses to better candidate" << endl;1946 }1947 }1948 */1949 2317 } else { 1950 if (DEBUG) { 1951 cout << "Doesn't satisfy requirements for circumscribing circle" << endl; 1952 } 2318 cerr << Verbose(1) << "ERROR: The projected center of the old sphere has radius " << radius << " instead of " << CircleRadius << "." << endl; 1953 2319 } 1954 2320 } else { 1955 if (DEBUG) { 1956 cout << "identisch mit Ursprungslinie" << endl; 1957 } 1958 } 1959 1960 if (RecursionLevel < 9) { // Five is the recursion level threshold. 1961 for (int i = 0; i < mol->NumberOfBondsPerAtom[Candidate->nr]; i++) { // go through all bond 1962 Walker = mol->ListOfBondsPerAtom[Candidate->nr][i]->GetOtherAtom(Candidate); 1963 if (Walker == Parent) { // don't go back the same bond 1964 continue; 1965 } else { 1966 Find_next_suitable_point(a, b, Walker, Candidate, RecursionLevel+1, Chord, d1, OldNormal, Opt_Candidate, Opt_Mittelpunkt, Storage, RADIUS, mol); //call function again 1967 } 1968 } 1969 } 1970 }; 1971 1972 /** This function finds a triangle to a line, adjacent to an existing one. 1973 * @param out output stream for debugging 1974 * @param tecplot output stream for writing found triangles in TecPlot format 1975 * @param mol molecule structure with all atoms and bonds 1976 * @param Line current baseline to search from 1977 * @param T current triangle which \a Line is edge of 1978 * @param RADIUS radius of the rolling ball 1979 * @param N number of found triangles 1980 * @param *filename filename base for intermediate envelopes 1981 */ 1982 bool Tesselation::Find_next_suitable_triangle(ofstream *out, ofstream *tecplot, 1983 molecule* mol, BoundaryLineSet &Line, BoundaryTriangleSet &T, 1984 const double& RADIUS, int N, const char *tempbasename) 1985 { 1986 cout << Verbose(1) << "Begin of Find_next_suitable_triangle\n"; 1987 Vector direction1; 1988 Vector helper; 1989 Vector Chord; 1990 ofstream *tempstream = NULL; 1991 char NumberName[255]; 1992 double tmp; 1993 //atom* Walker; 1994 atom* OldThirdPoint; 1995 1996 double Storage[3]; 1997 Storage[0] = -2.; // This direction is either +1 or -1 one, so any result will take precedence over initial values 1998 Storage[1] = -2.; // This is also lower then any value produced by an eligible atom, which are all positive 1999 Storage[2] = 9999999.; 2000 atom* Opt_Candidate = NULL; 2001 Vector Opt_Mittelpunkt; 2002 2003 cout << Verbose(1) << "Current baseline is " << Line << " of triangle " << T << "." << endl; 2004 2005 helper.CopyVector(&(Line.endpoints[0]->node->x)); 2006 for (int i = 0; i < 3; i++) { 2007 if (T.endpoints[i]->node->nr != Line.endpoints[0]->node->nr && T.endpoints[i]->node->nr != Line.endpoints[1]->node->nr) { 2008 OldThirdPoint = T.endpoints[i]->node; 2009 helper.SubtractVector(&T.endpoints[i]->node->x); 2010 break; 2011 } 2012 } 2013 2014 direction1.CopyVector(&Line.endpoints[0]->node->x); 2015 direction1.SubtractVector(&Line.endpoints[1]->node->x); 2016 direction1.VectorProduct(&(T.NormalVector)); 2017 2018 if (direction1.ScalarProduct(&helper) < 0) { 2019 direction1.Scale(-1); 2020 } 2021 cout << Verbose(2) << "Looking in direction " << direction1 << " for candidates.\n"; 2022 2023 Chord.CopyVector(&(Line.endpoints[0]->node->x)); // bring into calling function 2024 Chord.SubtractVector(&(Line.endpoints[1]->node->x)); 2025 cout << Verbose(2) << "Baseline vector is " << Chord << ".\n"; 2026 2027 2028 Vector Umkreismittelpunkt, a, b, c; 2029 double alpha, beta, gamma; 2030 a.CopyVector(&(T.endpoints[0]->node->x)); 2031 b.CopyVector(&(T.endpoints[1]->node->x)); 2032 c.CopyVector(&(T.endpoints[2]->node->x)); 2033 a.SubtractVector(&(T.endpoints[1]->node->x)); 2034 b.SubtractVector(&(T.endpoints[2]->node->x)); 2035 c.SubtractVector(&(T.endpoints[0]->node->x)); 2036 2037 alpha = M_PI - a.Angle(&c); 2038 beta = M_PI - b.Angle(&a); 2039 gamma = M_PI - c.Angle(&b); 2040 if (fabs(M_PI - alpha - beta - gamma) > MYEPSILON) 2041 cerr << Verbose(0) << "WARNING: sum of angles for candidate triangle " << (alpha + beta + gamma)/M_PI*180. << " != 180.\n"; 2042 2043 Umkreismittelpunkt.Zero(); 2044 helper.CopyVector(&T.endpoints[0]->node->x); 2045 helper.Scale(sin(2.*alpha)); 2046 Umkreismittelpunkt.AddVector(&helper); 2047 helper.CopyVector(&T.endpoints[1]->node->x); 2048 helper.Scale(sin(2.*beta)); 2049 Umkreismittelpunkt.AddVector(&helper); 2050 helper.CopyVector(&T.endpoints[2]->node->x); 2051 helper.Scale(sin(2.*gamma)); 2052 Umkreismittelpunkt.AddVector(&helper); 2053 //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) ; 2054 //cout << "UmkreisMittelpunkt is " << Umkreismittelpunkt.x[0] << " "<< Umkreismittelpunkt.x[1] << " "<< Umkreismittelpunkt.x[2] << " "<< endl; 2055 Umkreismittelpunkt.Scale(1/(sin(2*alpha) + sin(2*beta) + sin(2*gamma))); 2056 //cout << "UmkreisMittelpunkt is " << Umkreismittelpunkt.x[0] << " "<< Umkreismittelpunkt.x[1] << " "<< Umkreismittelpunkt.x[2] << " "<< endl; 2057 cout << " We look over line " << Line << " in direction " << direction1.x[0] << " " << direction1.x[1] << " " << direction1.x[2] << " " << endl; 2058 cout << " Old Normal is " << (T.NormalVector.x)[0] << " " << T.NormalVector.x[1] << " " << (T.NormalVector.x)[2] << " " << endl; 2059 2060 cout << Verbose(2) << "Base triangle has sides " << a << ", " << b << ", " << c << " with angles " << alpha/M_PI*180. << ", " << beta/M_PI*180. << ", " << gamma/M_PI*180. << "." << endl; 2061 cout << Verbose(2) << "Center of circumference is " << Umkreismittelpunkt << "." << endl; 2062 if (DEBUG) 2063 cout << Verbose(3) << "Check of relative endpoints (same distance, equally spreaded): "<< endl; 2064 tmp = 0; 2065 for (int i=0;i<NDIM;i++) { 2066 helper.CopyVector(&T.endpoints[i]->node->x); 2067 helper.SubtractVector(&Umkreismittelpunkt); 2068 if (DEBUG) 2069 cout << Verbose(3) << "Endpoint[" << i << "]: " << helper << " with length " << helper.Norm() << "." << endl; 2070 if (tmp == 0) // set on first time for comparison against next ones 2071 tmp = helper.Norm(); 2072 if (fabs(helper.Norm() - tmp) > MYEPSILON) 2073 cerr << Verbose(1) << "WARNING: center of circumference is wrong!" << endl; 2074 } 2075 2076 cout << Verbose(1) << "Looking for third point candidates for triangle ... " << endl; 2077 2078 Find_next_suitable_point_via_Angle_of_Sphere(Line.endpoints[0]->node, Line.endpoints[1]->node, OldThirdPoint, Line.endpoints[0]->node, Line.endpoints[1]->node, 0, &Chord, &direction1, &(T.NormalVector), Umkreismittelpunkt, Opt_Candidate, Storage, RADIUS, mol); 2079 Find_next_suitable_point_via_Angle_of_Sphere(Line.endpoints[0]->node, Line.endpoints[1]->node, OldThirdPoint, Line.endpoints[1]->node, Line.endpoints[0]->node, 0, &Chord, &direction1, &(T.NormalVector), Umkreismittelpunkt, Opt_Candidate, Storage, RADIUS, mol); 2080 if (Opt_Candidate == NULL) { 2081 cerr << "WARNING: Could not find a suitable candidate." << endl; 2082 return false; 2083 } 2084 cout << Verbose(1) << " Optimal candidate is " << *Opt_Candidate << endl; 2085 2086 // check whether all edges of the new triangle still have space for one more triangle (i.e. TriangleCount <2) 2087 bool flag = CheckPresenceOfTriangle(out, Opt_Candidate, Line.endpoints[0]->node, Line.endpoints[1]->node); 2088 2089 if (flag) { // if so, add 2090 AddTrianglePoint(Opt_Candidate, 0); 2091 AddTrianglePoint(Line.endpoints[0]->node, 1); 2092 AddTrianglePoint(Line.endpoints[1]->node, 2); 2093 2094 AddTriangleLine(TPS[0], TPS[1], 0); 2095 AddTriangleLine(TPS[0], TPS[2], 1); 2096 AddTriangleLine(TPS[1], TPS[2], 2); 2097 2098 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount); 2099 AddTriangleToLines(); 2100 2101 BTS->GetNormalVector(BTS->NormalVector); 2102 2103 if ((BTS->NormalVector.ScalarProduct(&(T.NormalVector)) < 0 && Storage[0] > 0) || (BTS->NormalVector.ScalarProduct(&(T.NormalVector)) > 0 && Storage[0] < 0) || (fabs(Storage[0]) < MYEPSILON && Storage[1]*BTS->NormalVector.ScalarProduct(&direction1) < 0) ) { 2104 BTS->NormalVector.Scale(-1); 2105 }; 2106 cout << Verbose(1) << "New triangle with " << *BTS << " and normal vector " << BTS->NormalVector << " for this triangle ... " << endl; 2107 cout << Verbose(1) << "We have "<< TrianglesOnBoundaryCount << " for line " << Line << "." << endl; 2108 } else { // else, yell and do nothing 2109 cout << Verbose(1) << "This triangle consisting of "; 2110 cout << *Opt_Candidate << ", "; 2111 cout << *Line.endpoints[0]->node << " and "; 2112 cout << *Line.endpoints[1]->node << " "; 2113 cout << "is invalid!" << endl; 2114 return false; 2115 } 2116 2117 if ((TrianglesOnBoundaryCount % 10) == 0) { 2118 sprintf(NumberName, "-%d", TriangleFilesWritten); 2119 if (DoTecplotOutput) { 2120 string NameofTempFile(tempbasename); 2121 NameofTempFile.append(NumberName); 2122 NameofTempFile.append(TecplotSuffix); 2123 cout << Verbose(1) << "Writing temporary non convex hull to file " << NameofTempFile << ".\n"; 2124 tempstream = new ofstream(NameofTempFile.c_str(), ios::trunc); 2125 write_tecplot_file(out, tempstream, this, mol, TriangleFilesWritten); 2126 tempstream->close(); 2127 tempstream->flush(); 2128 delete(tempstream); 2129 } 2130 2131 if (DoRaster3DOutput) { 2132 string NameofTempFile(tempbasename); 2133 NameofTempFile.append(NumberName); 2134 NameofTempFile.append(Raster3DSuffix); 2135 cout << Verbose(1) << "Writing temporary non convex hull to file " << NameofTempFile << ".\n"; 2136 tempstream = new ofstream(NameofTempFile.c_str(), ios::trunc); 2137 write_raster3d_file(out, tempstream, this, mol); 2138 tempstream->close(); 2139 tempstream->flush(); 2140 delete(tempstream); 2141 } 2142 if (DoTecplotOutput || DoRaster3DOutput) 2143 TriangleFilesWritten++; 2144 } 2145 2146 cout << Verbose(1) << "End of Find_next_suitable_triangle\n"; 2147 return true; 2321 if (ThirdNode != NULL) 2322 cout << Verbose(1) << "Circumcircle for base line " << *BaseLine << " and third node " << *ThirdNode << " is too big!" << endl; 2323 else 2324 cout << Verbose(1) << "Circumcircle for base line " << *BaseLine << " is too big!" << endl; 2325 } 2326 2327 2328 cout << Verbose(1) << "End of Find_third_point_for_Tesselation" << endl; 2148 2329 }; 2149 2330 … … 2194 2375 2195 2376 2196 void Find_second_point_for_Tesselation(atom* a, atom* Candidate, atom* Parent, 2197 int RecursionLevel, Vector Oben, atom*& Opt_Candidate, double Storage[3], 2198 molecule* mol, double RADIUS) 2199 { 2200 cout << Verbose(2) << "Begin of Find_second_point_for_Tesselation, recursive level " << RecursionLevel << endl; 2201 int i; 2377 /** Finds the second point of starting triangle. 2378 * \param *a first atom 2379 * \param *Candidate pointer to candidate atom on return 2380 * \param Oben vector indicating the outside 2381 * \param Opt_Candidate reference to recommended candidate on return 2382 * \param Storage[3] array storing angles and other candidate information 2383 * \param RADIUS radius of virtual sphere 2384 * \param *LC LinkedCell structure with neighbouring atoms 2385 */ 2386 void Find_second_point_for_Tesselation(atom* a, atom* Candidate, Vector Oben, atom*& Opt_Candidate, double Storage[3], double RADIUS, LinkedCell *LC) 2387 { 2388 cout << Verbose(2) << "Begin of Find_second_point_for_Tesselation" << endl; 2202 2389 Vector AngleCheck; 2203 atom* Walker;2204 2390 double norm = -1., angle; 2205 2206 // check if we only have one unique point yet ... 2207 if (a != Candidate) { 2208 cout << Verbose(3) << "Current candidate is " << *Candidate << ": "; 2209 AngleCheck.CopyVector(&(Candidate->x)); 2210 AngleCheck.SubtractVector(&(a->x)); 2211 norm = AngleCheck.Norm(); 2212 // second point shall have smallest angle with respect to Oben vector 2213 if (norm < RADIUS) { 2214 angle = AngleCheck.Angle(&Oben); 2215 if (angle < Storage[0]) { 2216 //cout << Verbose(1) << "Old values of Storage: %lf %lf \n", Storage[0], Storage[1]); 2217 cout << "Is a better candidate with distance " << norm << " and " << angle << ".\n"; 2218 Opt_Candidate = Candidate; 2219 Storage[0] = AngleCheck.Angle(&Oben); 2220 //cout << Verbose(1) << "Changing something in Storage: %lf %lf. \n", Storage[0], Storage[2]); 2221 } else { 2222 cout << "Looses with angle " << angle << " to a better candidate " << *Opt_Candidate << endl; 2391 LinkedAtoms *List = NULL; 2392 int N[NDIM], Nlower[NDIM], Nupper[NDIM]; 2393 2394 if (LC->SetIndexToAtom(a)) { // get cell for the starting atom 2395 for(int i=0;i<NDIM;i++) // store indices of this cell 2396 N[i] = LC->n[i]; 2397 } else { 2398 cerr << "ERROR: Atom " << *a << " is not found in cell " << LC->index << "." << endl; 2399 return; 2400 } 2401 // then go through the current and all neighbouring cells and check the contained atoms for possible candidates 2402 cout << Verbose(2) << "LC Intervals:"; 2403 for (int i=0;i<NDIM;i++) { 2404 Nlower[i] = ((N[i]-1) >= 0) ? N[i]-1 : 0; 2405 Nupper[i] = ((N[i]+1) < LC->N[i]) ? N[i]+1 : LC->N[i]-1; 2406 cout << " [" << Nlower[i] << "," << Nupper[i] << "] "; 2407 } 2408 cout << endl; 2409 for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++) 2410 for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++) 2411 for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) { 2412 List = LC->GetCurrentCell(); 2413 //cout << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << "." << endl; 2414 if (List != NULL) { 2415 for (LinkedAtoms::iterator Runner = List->begin(); Runner != List->end(); Runner++) { 2416 Candidate = (*Runner); 2417 // check if we only have one unique point yet ... 2418 if (a != Candidate) { 2419 cout << Verbose(3) << "Current candidate is " << *Candidate << ": "; 2420 AngleCheck.CopyVector(&(Candidate->x)); 2421 AngleCheck.SubtractVector(&(a->x)); 2422 norm = AngleCheck.Norm(); 2423 // second point shall have smallest angle with respect to Oben vector 2424 if (norm < RADIUS) { 2425 angle = AngleCheck.Angle(&Oben); 2426 if (angle < Storage[0]) { 2427 //cout << Verbose(1) << "Old values of Storage: %lf %lf \n", Storage[0], Storage[1]); 2428 cout << "Is a better candidate with distance " << norm << " and " << angle << ".\n"; 2429 Opt_Candidate = Candidate; 2430 Storage[0] = AngleCheck.Angle(&Oben); 2431 //cout << Verbose(1) << "Changing something in Storage: %lf %lf. \n", Storage[0], Storage[2]); 2432 } else { 2433 cout << "Looses with angle " << angle << " to a better candidate " << *Opt_Candidate << endl; 2434 } 2435 } else { 2436 cout << "Refused due to Radius " << norm << endl; 2437 } 2438 } 2439 } 2440 } 2223 2441 } 2224 } else { 2225 cout << "Refused due to Radius " << norm << endl; 2226 } 2227 } 2228 2229 // if not recursed to deeply, look at all its bonds 2230 if (RecursionLevel < 7) { 2231 for (i = 0; i < mol->NumberOfBondsPerAtom[Candidate->nr]; i++) { 2232 Walker = mol->ListOfBondsPerAtom[Candidate->nr][i]->GetOtherAtom(Candidate); 2233 if (Walker == Parent) // don't go back along the bond we came from 2234 continue; 2235 else 2236 Find_second_point_for_Tesselation(a, Walker, Candidate, RecursionLevel + 1, Oben, Opt_Candidate, Storage, mol, RADIUS); 2237 } 2238 } 2239 cout << Verbose(2) << "End of Find_second_point_for_Tesselation, recursive level " << RecursionLevel << endl; 2442 cout << Verbose(2) << "End of Find_second_point_for_Tesselation" << endl; 2240 2443 }; 2241 2444 2242 void Tesselation::Find_starting_triangle(molecule* mol, const double RADIUS) 2445 /** Finds the starting triangle for find_non_convex_border(). 2446 * Looks at the outermost atom per axis, then Find_second_point_for_Tesselation() 2447 * for the second and Find_next_suitable_point_via_Angle_of_Sphere() for the third 2448 * point are called. 2449 * \param RADIUS radius of virtual rolling sphere 2450 * \param *LC LinkedCell structure with neighbouring atoms 2451 */ 2452 void Tesselation::Find_starting_triangle(ofstream *out, molecule *mol, const double RADIUS, LinkedCell *LC) 2243 2453 { 2244 2454 cout << Verbose(1) << "Begin of Find_starting_triangle\n"; 2245 2455 int i = 0; 2246 atom* Walker;2456 LinkedAtoms *List = NULL; 2247 2457 atom* FirstPoint; 2248 2458 atom* SecondPoint; 2249 atom* max_index[NDIM];2459 atom* MaxAtom[NDIM]; 2250 2460 double max_coordinate[NDIM]; 2251 2461 Vector Oben; 2252 2462 Vector helper; 2253 2463 Vector Chord; 2254 Vector CenterOfFirstLine; 2464 Vector SearchDirection; 2465 Vector OptCandidateCenter; 2255 2466 2256 2467 Oben.Zero(); 2257 2468 2258 2469 for (i = 0; i < 3; i++) { 2259 max_index[i] = NULL;2470 MaxAtom[i] = NULL; 2260 2471 max_coordinate[i] = -1; 2261 2472 } 2262 cout << Verbose(2) << "Molecule mol is there and has " << mol->AtomCount << " Atoms \n";2263 2473 2264 2474 // 1. searching topmost atom with respect to each axis 2265 Walker = mol->start; 2266 while (Walker->next != mol->end) { 2267 Walker = Walker->next; 2268 for (i = 0; i < 3; i++) { 2269 if (Walker->x.x[i] > max_coordinate[i]) { 2270 max_coordinate[i] = Walker->x.x[i]; 2271 max_index[i] = Walker; 2475 for (int i=0;i<NDIM;i++) { // each axis 2476 LC->n[i] = LC->N[i]-1; // current axis is topmost cell 2477 for (LC->n[(i+1)%NDIM]=0;LC->n[(i+1)%NDIM]<LC->N[(i+1)%NDIM];LC->n[(i+1)%NDIM]++) 2478 for (LC->n[(i+2)%NDIM]=0;LC->n[(i+2)%NDIM]<LC->N[(i+2)%NDIM];LC->n[(i+2)%NDIM]++) { 2479 List = LC->GetCurrentCell(); 2480 //cout << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << "." << endl; 2481 if (List != NULL) { 2482 for (LinkedAtoms::iterator Runner = List->begin();Runner != List->end();Runner++) { 2483 cout << Verbose(2) << "Current atom is " << *(*Runner) << "." << endl; 2484 if ((*Runner)->x.x[i] > max_coordinate[i]) { 2485 max_coordinate[i] = (*Runner)->x.x[i]; 2486 MaxAtom[i] = (*Runner); 2487 } 2488 } 2489 } else { 2490 cerr << "ERROR: The current cell " << LC->n[0] << "," << LC->n[1] << "," << LC->n[2] << " is invalid!" << endl; 2491 } 2272 2492 } 2273 }2274 2493 } 2275 2494 2276 2495 cout << Verbose(2) << "Found maximum coordinates: "; 2277 2496 for (int i=0;i<NDIM;i++) 2278 cout << i << ": " << * max_index[i] << "\t";2497 cout << i << ": " << *MaxAtom[i] << "\t"; 2279 2498 cout << endl; 2280 //Koennen dies fuer alle Richtungen, legen hier erstmal Richtung auf k=0 2281 const int k = 1; 2499 const int k = 1; // arbitrary choice 2282 2500 Oben.x[k] = 1.; 2283 FirstPoint = max_index[k]; 2284 2285 cout << Verbose(1) << "Coordinates of start atom " << *FirstPoint << " at " << FirstPoint->x << " with " << mol->NumberOfBondsPerAtom[FirstPoint->nr] << " bonds." << endl; 2286 double Storage[3]; 2501 FirstPoint = MaxAtom[k]; 2502 cout << Verbose(1) << "Coordinates of start atom " << *FirstPoint << " at " << FirstPoint->x << "." << endl; 2503 2504 // add first point 2505 AddTrianglePoint(FirstPoint, 0); 2506 2507 double ShortestAngle; 2287 2508 atom* Opt_Candidate = NULL; 2288 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. 2289 Storage[1] = 999999.; // This will be an angle looking for the third point. 2290 Storage[2] = 999999.; 2291 2292 Find_second_point_for_Tesselation(FirstPoint, FirstPoint, FirstPoint, 0, Oben, Opt_Candidate, Storage, mol, RADIUS); // we give same point as next candidate as its bonds are looked into in find_second_... 2509 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. 2510 2511 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_... 2293 2512 SecondPoint = Opt_Candidate; 2294 2513 cout << Verbose(1) << "Found second point is " << *SecondPoint << " at " << SecondPoint->x << ".\n"; 2514 2515 // add second point and first baseline 2516 AddTrianglePoint(SecondPoint, 1); 2517 AddTriangleLine(TPS[0], TPS[1], 0); 2295 2518 2296 2519 helper.CopyVector(&(FirstPoint->x)); … … 2300 2523 Oben.Normalize(); 2301 2524 helper.VectorProduct(&Oben); 2302 Storage[0] = -2.; // This will indicate the quadrant. 2303 Storage[1] = 9999999.; // This will be an angle looking for the third point. 2304 Storage[2] = 9999999.; 2525 ShortestAngle = 2.*M_PI; // This will indicate the quadrant. 2305 2526 2306 2527 Chord.CopyVector(&(FirstPoint->x)); // bring into calling function 2307 2528 Chord.SubtractVector(&(SecondPoint->x)); 2529 double radius = Chord.ScalarProduct(&Chord); 2530 double CircleRadius = sqrt(RADIUS*RADIUS - radius/4.); 2531 helper.CopyVector(&Oben); 2532 helper.Scale(CircleRadius); 2308 2533 // Now, oben and helper are two orthonormalized vectors in the plane defined by Chord (not normalized) 2309 2534 … … 2311 2536 // look in one direction of baseline for initial candidate 2312 2537 Opt_Candidate = NULL; 2313 CenterOfFirstLine.CopyVector(&Chord); 2314 CenterOfFirstLine.Scale(0.5); 2315 CenterOfFirstLine.AddVector(&(SecondPoint->x)); 2316 2317 cout << Verbose(1) << "Looking for third point candidates from " << *FirstPoint << " onward ...\n"; 2318 Find_next_suitable_point_via_Angle_of_Sphere(FirstPoint, SecondPoint, SecondPoint, SecondPoint, FirstPoint, 0, &Chord, &helper, &Oben, CenterOfFirstLine, Opt_Candidate, Storage, RADIUS, mol); 2319 // look in other direction of baseline for possible better candidate 2320 cout << Verbose(1) << "Looking for third point candidates from " << *SecondPoint << " onward ...\n"; 2321 Find_next_suitable_point_via_Angle_of_Sphere(FirstPoint, SecondPoint, SecondPoint, FirstPoint, SecondPoint, 0, &Chord, &helper, &Oben, CenterOfFirstLine, Opt_Candidate, Storage, RADIUS, mol); 2538 SearchDirection.MakeNormalVector(&Chord, &Oben); // whether we look "left" first or "right" first is not important ... 2539 2540 cout << Verbose(1) << "Looking for third point candidates ...\n"; 2541 Find_third_point_for_Tesselation(Oben, SearchDirection, helper, BLS[0], NULL, Opt_Candidate, &OptCandidateCenter, &ShortestAngle, RADIUS, LC); 2322 2542 cout << Verbose(1) << "Third Point is " << *Opt_Candidate << endl; 2323 2543 2544 // add third point 2545 AddTrianglePoint(Opt_Candidate, 2); 2546 2324 2547 // FOUND Starting Triangle: FirstPoint, SecondPoint, Opt_Candidate 2325 2548 2326 // Finally, we only have to add the found points 2327 AddTrianglePoint(FirstPoint, 0); 2328 AddTrianglePoint(SecondPoint, 1); 2329 AddTrianglePoint(Opt_Candidate, 2); 2330 // ... and respective lines 2331 AddTriangleLine(TPS[0], TPS[1], 0); 2549 // Finally, we only have to add the found further lines 2332 2550 AddTriangleLine(TPS[1], TPS[2], 1); 2333 2551 AddTriangleLine(TPS[0], TPS[2], 2); … … 2336 2554 AddTriangleToLines(); 2337 2555 // ... and calculate its normal vector (with correct orientation) 2338 Oben.Scale(-1.); 2339 BTS->GetNormalVector(Oben); 2556 OptCandidateCenter.Scale(-1.); 2557 cout << Verbose(2) << "Oben is currently " << OptCandidateCenter << "." << endl; 2558 BTS->GetNormalVector(OptCandidateCenter); 2340 2559 cout << Verbose(0) << "==> The found starting triangle consists of " << *FirstPoint << ", " << *SecondPoint << " and " << *Opt_Candidate << " with normal vector " << BTS->NormalVector << ".\n"; 2560 cout << Verbose(2) << "Projection is " << BTS->NormalVector.Projection(&Oben) << "." << endl; 2341 2561 cout << Verbose(1) << "End of Find_starting_triangle\n"; 2342 2562 }; 2343 2563 2344 void Find_non_convex_border(ofstream *out, ofstream *tecplot, molecule* mol, const char *filename, const double RADIUS) 2564 /** This function finds a triangle to a line, adjacent to an existing one. 2565 * @param out output stream for debugging 2566 * @param *mol molecule with Atom's and Bond's 2567 * @param Line current baseline to search from 2568 * @param T current triangle which \a Line is edge of 2569 * @param RADIUS radius of the rolling ball 2570 * @param N number of found triangles 2571 * @param *filename filename base for intermediate envelopes 2572 * @param *LC LinkedCell structure with neighbouring atoms 2573 */ 2574 bool Tesselation::Find_next_suitable_triangle(ofstream *out, 2575 molecule *mol, BoundaryLineSet &Line, BoundaryTriangleSet &T, 2576 const double& RADIUS, int N, const char *tempbasename, LinkedCell *LC) 2577 { 2578 cout << Verbose(1) << "Begin of Find_next_suitable_triangle\n"; 2579 ofstream *tempstream = NULL; 2580 char NumberName[255]; 2581 2582 atom* Opt_Candidate = NULL; 2583 Vector OptCandidateCenter; 2584 2585 Vector CircleCenter; 2586 Vector CirclePlaneNormal; 2587 Vector OldSphereCenter; 2588 Vector SearchDirection; 2589 Vector helper; 2590 atom *ThirdNode = NULL; 2591 double ShortestAngle = 2.*M_PI; // This will indicate the quadrant. 2592 double radius, CircleRadius; 2593 2594 cout << Verbose(1) << "Current baseline is " << Line << " of triangle " << T << "." << endl; 2595 for (int i=0;i<3;i++) 2596 if ((T.endpoints[i]->node != Line.endpoints[0]->node) && (T.endpoints[i]->node != Line.endpoints[1]->node)) 2597 ThirdNode = T.endpoints[i]->node; 2598 2599 // construct center of circle 2600 CircleCenter.CopyVector(&Line.endpoints[0]->node->x); 2601 CircleCenter.AddVector(&Line.endpoints[1]->node->x); 2602 CircleCenter.Scale(0.5); 2603 2604 // construct normal vector of circle 2605 CirclePlaneNormal.CopyVector(&Line.endpoints[0]->node->x); 2606 CirclePlaneNormal.SubtractVector(&Line.endpoints[1]->node->x); 2607 2608 // calculate squared radius of circle 2609 radius = CirclePlaneNormal.ScalarProduct(&CirclePlaneNormal); 2610 if (radius/4. < RADIUS*RADIUS) { 2611 CircleRadius = RADIUS*RADIUS - radius/4.; 2612 CirclePlaneNormal.Normalize(); 2613 cout << Verbose(2) << "INFO: CircleCenter is at " << CircleCenter << ", CirclePlaneNormal is " << CirclePlaneNormal << " with circle radius " << sqrt(CircleRadius) << "." << endl; 2614 2615 // construct old center 2616 GetCenterofCircumcircle(&OldSphereCenter, &(T.endpoints[0]->node->x), &(T.endpoints[1]->node->x), &(T.endpoints[2]->node->x)); 2617 helper.CopyVector(&T.NormalVector); // normal vector ensures that this is correct center of the two possible ones 2618 radius = Line.endpoints[0]->node->x.DistanceSquared(&OldSphereCenter); 2619 helper.Scale(sqrt(RADIUS*RADIUS - radius)); 2620 OldSphereCenter.AddVector(&helper); 2621 OldSphereCenter.SubtractVector(&CircleCenter); 2622 cout << Verbose(2) << "INFO: OldSphereCenter is at " << OldSphereCenter << "." << endl; 2623 2624 // construct SearchDirection 2625 SearchDirection.MakeNormalVector(&T.NormalVector, &CirclePlaneNormal); 2626 helper.CopyVector(&Line.endpoints[0]->node->x); 2627 helper.SubtractVector(&ThirdNode->x); 2628 if (helper.ScalarProduct(&SearchDirection) < -HULLEPSILON) // ohoh, SearchDirection points inwards! 2629 SearchDirection.Scale(-1.); 2630 SearchDirection.ProjectOntoPlane(&OldSphereCenter); 2631 SearchDirection.Normalize(); 2632 cout << Verbose(2) << "INFO: SearchDirection is " << SearchDirection << "." << endl; 2633 if (fabs(OldSphereCenter.ScalarProduct(&SearchDirection)) > HULLEPSILON) { // rotated the wrong way! 2634 cerr << "ERROR: SearchDirection and RelativeOldSphereCenter are still not orthogonal!" << endl; 2635 } 2636 2637 // add third point 2638 cout << Verbose(1) << "Looking for third point candidates for triangle ... " << endl; 2639 Find_third_point_for_Tesselation(T.NormalVector, SearchDirection, OldSphereCenter, &Line, ThirdNode, Opt_Candidate, &OptCandidateCenter, &ShortestAngle, RADIUS, LC); 2640 2641 } else { 2642 cout << Verbose(1) << "Circumcircle for base line " << Line << " and base triangle " << T << " is too big!" << endl; 2643 } 2644 2645 if (Opt_Candidate == NULL) { 2646 cerr << "WARNING: Could not find a suitable candidate." << endl; 2647 return false; 2648 } 2649 cout << Verbose(1) << " Optimal candidate is " << *Opt_Candidate << " with circumsphere's center at " << OptCandidateCenter << "." << endl; 2650 2651 // check whether all edges of the new triangle still have space for one more triangle (i.e. TriangleCount <2) 2652 bool flag = CheckPresenceOfTriangle(out, Opt_Candidate, Line.endpoints[0]->node, Line.endpoints[1]->node); 2653 2654 if (flag) { // if so, add 2655 AddTrianglePoint(Opt_Candidate, 0); 2656 AddTrianglePoint(Line.endpoints[0]->node, 1); 2657 AddTrianglePoint(Line.endpoints[1]->node, 2); 2658 2659 AddTriangleLine(TPS[0], TPS[1], 0); 2660 AddTriangleLine(TPS[0], TPS[2], 1); 2661 AddTriangleLine(TPS[1], TPS[2], 2); 2662 2663 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount); 2664 AddTriangleToLines(); 2665 2666 OptCandidateCenter.Scale(-1.); 2667 BTS->GetNormalVector(OptCandidateCenter); 2668 OptCandidateCenter.Scale(-1.); 2669 2670 cout << "--> New triangle with " << *BTS << " and normal vector " << BTS->NormalVector << " for this triangle ... " << endl; 2671 cout << Verbose(1) << "We have "<< TrianglesOnBoundaryCount << " for line " << Line << "." << endl; 2672 } else { // else, yell and do nothing 2673 cout << Verbose(1) << "This triangle consisting of "; 2674 cout << *Opt_Candidate << ", "; 2675 cout << *Line.endpoints[0]->node << " and "; 2676 cout << *Line.endpoints[1]->node << " "; 2677 cout << "is invalid!" << endl; 2678 return false; 2679 } 2680 2681 if (flag && (DoSingleStepOutput && (TrianglesOnBoundaryCount % 10 == 0))) { // if we have a new triangle and want to output each new triangle configuration 2682 sprintf(NumberName, "-%04d-%s_%s_%s", TriangleFilesWritten, BTS->endpoints[0]->node->Name, BTS->endpoints[1]->node->Name, BTS->endpoints[2]->node->Name); 2683 if (DoTecplotOutput) { 2684 string NameofTempFile(tempbasename); 2685 NameofTempFile.append(NumberName); 2686 for(size_t npos = NameofTempFile.find_first_of(' '); npos != string::npos; npos = NameofTempFile.find(' ', npos)) 2687 NameofTempFile.erase(npos, 1); 2688 NameofTempFile.append(TecplotSuffix); 2689 cout << Verbose(1) << "Writing temporary non convex hull to file " << NameofTempFile << ".\n"; 2690 tempstream = new ofstream(NameofTempFile.c_str(), ios::trunc); 2691 write_tecplot_file(out, tempstream, this, mol, TriangleFilesWritten); 2692 tempstream->close(); 2693 tempstream->flush(); 2694 delete(tempstream); 2695 } 2696 2697 if (DoRaster3DOutput) { 2698 string NameofTempFile(tempbasename); 2699 NameofTempFile.append(NumberName); 2700 for(size_t npos = NameofTempFile.find_first_of(' '); npos != string::npos; npos = NameofTempFile.find(' ', npos)) 2701 NameofTempFile.erase(npos, 1); 2702 NameofTempFile.append(Raster3DSuffix); 2703 cout << Verbose(1) << "Writing temporary non convex hull to file " << NameofTempFile << ".\n"; 2704 tempstream = new ofstream(NameofTempFile.c_str(), ios::trunc); 2705 write_raster3d_file(out, tempstream, this, mol); 2706 // include the current position of the virtual sphere in the temporary raster3d file 2707 // make the circumsphere's center absolute again 2708 helper.CopyVector(&Line.endpoints[0]->node->x); 2709 helper.AddVector(&Line.endpoints[1]->node->x); 2710 helper.Scale(0.5); 2711 OptCandidateCenter.AddVector(&helper); 2712 Vector *center = mol->DetermineCenterOfAll(out); 2713 OptCandidateCenter.AddVector(center); 2714 delete(center); 2715 // and add to file plus translucency object 2716 *tempstream << "# current virtual sphere\n"; 2717 *tempstream << "8\n 25.0 0.6 -1.0 -1.0 -1.0 0.2 0 0 0 0\n"; 2718 *tempstream << "2\n " << OptCandidateCenter.x[0] << " " << OptCandidateCenter.x[1] << " " << OptCandidateCenter.x[2] << "\t" << RADIUS << "\t1 0 0\n"; 2719 *tempstream << "9\n terminating special property\n"; 2720 tempstream->close(); 2721 tempstream->flush(); 2722 delete(tempstream); 2723 } 2724 if (DoTecplotOutput || DoRaster3DOutput) 2725 TriangleFilesWritten++; 2726 } 2727 2728 cout << Verbose(1) << "End of Find_next_suitable_triangle\n"; 2729 return true; 2730 }; 2731 2732 /** Tesselates the non convex boundary by rolling a virtual sphere along the surface of the molecule. 2733 * \param *out output stream for debugging 2734 * \param *mol molecule structure with Atom's and Bond's 2735 * \param *Tess Tesselation filled with points, lines and triangles on boundary on return 2736 * \param *LCList linked cell list of all atoms 2737 * \param *filename filename prefix for output of vertex data 2738 * \para RADIUS radius of the virtual sphere 2739 */ 2740 void Find_non_convex_border(ofstream *out, molecule* mol, class Tesselation *Tess, class LinkedCell *LCList, const char *filename, const double RADIUS) 2345 2741 { 2346 2742 int N = 0; 2347 struct Tesselation *Tess = new Tesselation; 2348 cout << Verbose(1) << "Entering search for non convex hull. " << endl; 2349 cout << flush; 2743 bool freeTess = false; 2744 *out << Verbose(1) << "Entering search for non convex hull. " << endl; 2745 if (Tess == NULL) { 2746 *out << Verbose(1) << "Allocating Tesselation struct ..." << endl; 2747 Tess = new Tesselation; 2748 freeTess = true; 2749 } 2750 bool freeLC = false; 2350 2751 LineMap::iterator baseline; 2351 cout << Verbose(0) << "Begin of Find_non_convex_border\n";2752 *out << Verbose(0) << "Begin of Find_non_convex_border\n"; 2352 2753 bool flag = false; // marks whether we went once through all baselines without finding any without two triangles 2353 2754 bool failflag = false; 2354 if ((mol->first->next == mol->last) || (mol->last->previous == mol->first)) 2355 mol->CreateAdjacencyList((ofstream *)&cout, 1.6, true); 2356 2357 Tess->Find_starting_triangle(mol, RADIUS); 2755 2756 if (LCList == NULL) { 2757 LCList = new LinkedCell(mol, 2.*RADIUS); 2758 freeLC = true; 2759 } 2760 2761 Tess->Find_starting_triangle(out, mol, RADIUS, LCList); 2358 2762 2359 2763 baseline = Tess->LinesOnBoundary.begin(); 2360 2764 while ((baseline != Tess->LinesOnBoundary.end()) || (flag)) { 2361 2765 if (baseline->second->TrianglesCount == 1) { 2362 failflag = Tess->Find_next_suitable_triangle(out, tecplot, mol, *(baseline->second), *(((baseline->second->triangles.begin()))->second), RADIUS, N, filename); //the line is there, so there is a triangle, but only one.2766 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. 2363 2767 flag = flag || failflag; 2364 2768 if (!failflag) … … 2374 2778 } 2375 2779 } 2376 if (failflag) { 2377 cout << Verbose(1) << "Writing final tecplot file\n"; 2378 if (DoTecplotOutput) 2780 if (1) { //failflag) { 2781 *out << Verbose(1) << "Writing final tecplot file\n"; 2782 if (DoTecplotOutput) { 2783 string OutputName(filename); 2784 OutputName.append(TecplotSuffix); 2785 ofstream *tecplot = new ofstream(OutputName.c_str()); 2379 2786 write_tecplot_file(out, tecplot, Tess, mol, -1); 2380 if (DoRaster3DOutput) 2381 write_raster3d_file(out, tecplot, Tess, mol); 2787 tecplot->close(); 2788 delete(tecplot); 2789 } 2790 if (DoRaster3DOutput) { 2791 string OutputName(filename); 2792 OutputName.append(Raster3DSuffix); 2793 ofstream *raster = new ofstream(OutputName.c_str()); 2794 write_raster3d_file(out, raster, Tess, mol); 2795 raster->close(); 2796 delete(raster); 2797 } 2382 2798 } else { 2383 2799 cerr << "ERROR: Could definately not find all necessary triangles!" << endl; 2384 2800 } 2385 2386 cout << Verbose(0) << "End of Find_non_convex_border\n"; 2387 delete(Tess); 2801 if (freeTess) 2802 delete(Tess); 2803 if (freeLC) 2804 delete(LCList); 2805 *out << Verbose(0) << "End of Find_non_convex_border\n"; 2388 2806 }; 2389 2807 2808 /** Finds a hole of sufficient size in \a this molecule to embed \a *srcmol into it. 2809 * \param *out output stream for debugging 2810 * \param *srcmol molecule to embed into 2811 * \return *Vector new center of \a *srcmol for embedding relative to \a this 2812 */ 2813 Vector* molecule::FindEmbeddingHole(ofstream *out, molecule *srcmol) 2814 { 2815 Vector *Center = new Vector; 2816 Center->Zero(); 2817 // calculate volume/shape of \a *srcmol 2818 2819 // find embedding holes 2820 2821 // if more than one, let user choose 2822 2823 // return embedding center 2824 return Center; 2825 }; 2826
Note:
See TracChangeset
for help on using the changeset viewer.
