VoronoiTessellation.hpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2009
00004 
00005 University of Oxford means the Chancellor, Masters and Scholars of the
00006 University of Oxford, having an administrative office at Wellington
00007 Square, Oxford OX1 2JD, UK.
00008 
00009 This file is part of Chaste.
00010 
00011 Chaste is free software: you can redistribute it and/or modify it
00012 under the terms of the GNU Lesser General Public License as published
00013 by the Free Software Foundation, either version 2.1 of the License, or
00014 (at your option) any later version.
00015 
00016 Chaste is distributed in the hope that it will be useful, but WITHOUT
00017 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00019 License for more details. The offer of Chaste under the terms of the
00020 License is subject to the License being interpreted in accordance with
00021 English Law and subject to any action against the University of Oxford
00022 being under the jurisdiction of the English Courts.
00023 
00024 You should have received a copy of the GNU Lesser General Public License
00025 along with Chaste. If not, see <http://www.gnu.org/licenses/>.
00026 
00027 */
00028 
00029 
00030 #ifndef VORONOITESSELLATION_HPP_
00031 #define VORONOITESSELLATION_HPP_
00032 
00033 #include "UblasCustomFunctions.hpp"
00034 #include "TetrahedralMesh.hpp"
00035 #include "VoronoiCell.hpp"
00036 
00037 #include <cmath>
00038 #include <vector>
00039 
00040 template<unsigned DIM>
00041 class VoronoiTessellation
00042 {
00043 private:
00044     friend class TestVoronoiTessellation;
00045     friend class InventorVoronoiWriter;
00046 
00047     TetrahedralMesh<DIM,DIM>& mrMesh;
00051     std::vector< c_vector<double,DIM>* > mVertices;
00055     std::vector< Face<DIM>* > mFaces;
00059     std::vector< VoronoiCell > mVoronoiCells;
00060 
00061 
00062     class VertexAndAngle
00063     {
00064     public:
00065         c_vector< double ,DIM >* mpVertex;
00066         double mAngle;
00067         bool operator<(const VertexAndAngle& other) const
00068         {
00069             return mAngle < other.mAngle;
00070         }
00071     };
00072 
00073     void GenerateVerticesFromElementCircumcentres();
00074 
00080     double ReturnPolarAngle(double x, double y) const;
00081 
00082     void Initialise(TetrahedralMesh<2,2>& rMesh);
00083     void Initialise(TetrahedralMesh<3,3>& rMesh);
00084 
00085 
00086 public:
00087 
00088     /***
00089      * Constructor. Create a tesselation of the given mesh which must be Delaunay
00090      * (see TetrahedralMesh::CheckVoronoi).
00091      */
00092     VoronoiTessellation(TetrahedralMesh<DIM,DIM>& rMesh);
00093 
00094     ~VoronoiTessellation();
00095 
00096     /***
00097      * Get a VoronoiCell.
00098      *
00099      * @param index The index of the cell is the index of the corresponding node in the original mesh.
00100      * If the corresponding node was on the boundary, this will return a cell with no faces.
00101      */
00102     const VoronoiCell& rGetCell(unsigned index) const;
00103     const Face<DIM>* GetFace(unsigned index) const;
00104     unsigned GetNumFaces();
00105 
00106     double GetFaceArea(unsigned index) const;
00107     double GetFacePerimeter(unsigned index) const;
00108 
00109     double GetEdgeLength(unsigned nodeIndex1, unsigned nodeIndex2) const;
00110 
00111     unsigned GetNumVertices();
00112     c_vector<double,DIM>* GetVertex(unsigned index);
00113 
00114     unsigned GetNumCells();
00115 
00116 };
00117 
00118 
00119 template<unsigned DIM>
00120 VoronoiTessellation<DIM>::VoronoiTessellation(TetrahedralMesh<DIM,DIM>& rMesh)
00121     : mrMesh(rMesh)
00122 {
00123     #define COVERAGE_IGNORE
00124     assert(DIM==2 || DIM==3);
00125     #undef COVERAGE_IGNORE
00126 
00127     if(DIM==2)
00128     {
00129     }
00130     else
00131     {
00132         GenerateVerticesFromElementCircumcentres();
00133         mVoronoiCells.resize(rMesh.GetNumAllNodes());
00134     }
00135 
00136     Initialise(rMesh);
00137 };
00138 
00139 
00140 template<unsigned DIM>
00141 void VoronoiTessellation<DIM>::Initialise(TetrahedralMesh<2,2>& rMesh)
00142 {
00143     for(unsigned i=0; i<rMesh.GetNumAllNodes(); i++)
00144     {
00145         // this edge is on the boundary
00146         Face<DIM>* p_face = new Face<DIM>;
00147         mFaces.push_back(p_face);
00148     }
00149 
00150 
00151     // loop over elements, for each element calculate circumcentre (=vertex), set that as a
00152     // vertex for each node(=face in 2d) of that element. Also loop over mesh-edges of the element
00153     // and add the vertex as a vertex for that vertex-edge
00154     c_matrix<double, DIM, DIM> jacobian, inverse_jacobian;
00155     double jacobian_det;
00156     for(unsigned i=0; i<mrMesh.GetNumElements(); i++)
00157     {
00158         mrMesh.GetInverseJacobianForElement(i, jacobian, jacobian_det, inverse_jacobian);
00159 
00160         c_vector<double,DIM+1> circumsphere = mrMesh.GetElement(i)->CalculateCircumsphere(jacobian, inverse_jacobian);
00161 
00162         c_vector<double,DIM>*  p_circumcentre = new c_vector<double, DIM>;
00163         for(unsigned j=0; j<DIM; j++)
00164         {
00165             (*p_circumcentre)(j)=circumsphere(j);
00166         }
00167         mVertices.push_back(p_circumcentre);
00168 
00169         for(unsigned node_index=0; node_index<DIM+1; node_index++)
00170         {
00171             unsigned node_global_index = mrMesh.GetElement(i)->GetNodeGlobalIndex(node_index);
00172             mFaces[node_global_index]->mVertices.push_back(p_circumcentre);
00173         }
00174     }
00175 
00176     // Reorder mVertices Anticlockwise
00177     for(unsigned i=0; i<mFaces.size(); i++)
00178     {
00179 
00180         std::vector< VertexAndAngle > vertices_and_angles;
00181         for(unsigned j=0; j<mFaces[i]->mVertices.size(); j++)
00182         {
00183 
00184             VertexAndAngle va;
00185             c_vector<double, DIM> centre_to_vertex;
00186             centre_to_vertex = *(mFaces[i]->mVertices[j]) - mrMesh.GetNode(i)->rGetLocation();
00187             va.mAngle = ReturnPolarAngle(centre_to_vertex(0), centre_to_vertex(1));
00188             va.mpVertex = mFaces[i]->mVertices[j];
00189             vertices_and_angles.push_back(va);
00190         }
00191         std::sort(vertices_and_angles.begin(), vertices_and_angles.end());
00192 
00193         // create face
00194         Face<DIM>* p_face = new Face<DIM>;
00195         for ( typename std::vector< VertexAndAngle >::iterator vertex_iterator = vertices_and_angles.begin();
00196               vertex_iterator !=vertices_and_angles.end();
00197               vertex_iterator++)
00198         {
00199             p_face->mVertices.push_back(vertex_iterator->mpVertex);
00200         }
00201 
00202 
00203         // add face to list of faces
00204         delete mFaces[i];
00205         mFaces[i] = p_face;
00206     }
00207 }
00208 
00209 
00210 template<unsigned DIM>
00211 void VoronoiTessellation<DIM>::Initialise(TetrahedralMesh<3,3>& rMesh)
00212 {
00213     #define COVERAGE_IGNORE
00214     assert(DIM==3);
00215     #undef COVERAGE_IGNORE
00216 
00217     // loop over each edge
00218     for (typename TetrahedralMesh<DIM,DIM>::EdgeIterator edge_iterator = mrMesh.EdgesBegin();
00219          edge_iterator != mrMesh.EdgesEnd();
00220          ++edge_iterator)
00221     {
00222         Node<DIM>* p_node_a = edge_iterator.GetNodeA();
00223         Node<DIM>* p_node_b = edge_iterator.GetNodeB();
00224 
00225         if ( p_node_a->IsBoundaryNode() && p_node_b->IsBoundaryNode() )
00226         {
00227             // this edge is on the boundary
00228             Face<DIM>* p_null_face = new Face<DIM>;
00229             mFaces.push_back(p_null_face);
00230         }
00231         else
00232         {
00233             std::set< unsigned >& node_a_element_indices = p_node_a->rGetContainingElementIndices();
00234             std::set< unsigned >& node_b_element_indices = p_node_b->rGetContainingElementIndices();
00235             std::set< unsigned > edge_element_indices;
00236             std::set_intersection(node_a_element_indices.begin(),
00237                                   node_a_element_indices.end(),
00238                                   node_b_element_indices.begin(),
00239                                   node_b_element_indices.end(),
00240                                   std::inserter(edge_element_indices, edge_element_indices.begin()));
00241             c_vector<double,DIM> edge_vector = p_node_b->rGetLocation() - p_node_a->rGetLocation();
00242             c_vector<double,DIM> mid_edge = edge_vector*0.5 + p_node_a->rGetLocation();
00243             unsigned element0_index=*(edge_element_indices.begin());
00244             c_vector<double,DIM> basis_vector1 = *(mVertices[element0_index]) - mid_edge;
00245             c_vector<double,DIM> basis_vector2;
00246             basis_vector2[0] = edge_vector[1]*basis_vector1[2] - edge_vector[2]*basis_vector1[1];
00247             basis_vector2[1] = edge_vector[2]*basis_vector1[0] - edge_vector[0]*basis_vector1[2];
00248             basis_vector2[2] = edge_vector[0]*basis_vector1[1] - edge_vector[1]*basis_vector1[0];
00249 
00250             std::vector< VertexAndAngle> vertices;
00251             // loop over each element containg this edge
00252             // the elements are those containing both nodes of the edge
00253 
00254             for (std::set< unsigned >::iterator element_index_iterator=edge_element_indices.begin();
00255                  element_index_iterator!=edge_element_indices.end();
00256                  element_index_iterator++)
00257             {
00258                 // Calculate angle
00259                 c_vector< double, DIM > vertex_vector = *(mVertices[*element_index_iterator]) - mid_edge;
00260 
00261                 double local_vertex_dot_basis_vector1 = inner_prod(vertex_vector, basis_vector1);
00262                 double local_vertex_dot_basis_vector2 = inner_prod(vertex_vector, basis_vector2);
00263 
00264 
00265                 VertexAndAngle va;
00266                 va.mAngle = ReturnPolarAngle(local_vertex_dot_basis_vector1, local_vertex_dot_basis_vector2);
00267                 va.mpVertex = mVertices[*element_index_iterator];
00268                 vertices.push_back(va);
00269             }
00270 
00271             // sort vertices by angle
00272             std::sort(vertices.begin(), vertices.end());
00273 
00274             // create face
00275             Face<DIM>* p_face = new Face<DIM>;
00276             for ( typename std::vector< VertexAndAngle >::iterator vertex_iterator = vertices.begin();
00277                   vertex_iterator !=vertices.end();
00278                   vertex_iterator++)
00279             {
00280                 p_face->mVertices.push_back(vertex_iterator->mpVertex);
00281             }
00282 
00283             // add face to list of faces
00284             mFaces.push_back(p_face);
00285             // .. and appropriate elements
00286 
00287             if (!p_node_a->IsBoundaryNode())
00288             {
00289                 mVoronoiCells[p_node_a->GetIndex()].mFaces.push_back(p_face);
00290                 mVoronoiCells[p_node_a->GetIndex()].mOrientations.push_back(true);
00291                 mVoronoiCells[p_node_a->GetIndex()].mCellCentre = p_node_a->rGetLocation();
00292             }
00293             if (!p_node_b->IsBoundaryNode())
00294             {
00295                 mVoronoiCells[p_node_b->GetIndex()].mFaces.push_back(p_face);
00296                 mVoronoiCells[p_node_b->GetIndex()].mOrientations.push_back(false);
00297                 mVoronoiCells[p_node_b->GetIndex()].mCellCentre = p_node_b->rGetLocation();
00298             }
00299         }
00300     }
00301 }
00302 
00303 
00304 
00305 
00306 template<unsigned DIM>
00307 VoronoiTessellation<DIM>::~VoronoiTessellation()
00308 {
00309     // delete faces
00310     for (typename std::vector< Face<DIM>* >::iterator face_iterator=mFaces.begin();
00311          face_iterator!=mFaces.end();
00312          face_iterator++)
00313     {
00314         delete *face_iterator;
00315     }
00316     // delete vertices
00317     for (typename std::vector< c_vector<double,DIM>* >::iterator vertex_iterator=mVertices.begin();
00318          vertex_iterator!=mVertices.end();
00319          vertex_iterator++)
00320     {
00321         delete *vertex_iterator;
00322     }
00323 };
00324 
00325 template<unsigned DIM>
00326 void VoronoiTessellation<DIM>::GenerateVerticesFromElementCircumcentres()
00327 {
00328 
00329     c_matrix<double, DIM, DIM> jacobian, inverse_jacobian;
00330     double jacobian_det;
00331     for(unsigned i=0; i<mrMesh.GetNumElements(); i++)
00332     {
00333         mrMesh.GetInverseJacobianForElement(i, jacobian, jacobian_det, inverse_jacobian);
00334 
00335         c_vector<double,DIM+1> circumsphere = mrMesh.GetElement(i)->CalculateCircumsphere(jacobian, inverse_jacobian);
00336 
00337         c_vector<double,DIM>*  p_circumcentre = new c_vector<double, DIM>;
00338         for(unsigned j=0; j<DIM; j++)
00339         {
00340             (*p_circumcentre)(j)=circumsphere(j);
00341         }
00342         mVertices.push_back(p_circumcentre);
00343     }
00344 };
00345 
00346 template<unsigned DIM>
00347 double VoronoiTessellation<DIM>::ReturnPolarAngle(double x, double y) const
00348 {
00349     if (x==0)
00350     {
00351         if (y>0)
00352         {
00353             return M_PI/2.0;
00354         }
00355         else if (y<0)
00356         {
00357             return -M_PI/2.0;
00358         }
00359         else
00360         {
00361             EXCEPTION("Tried to compute polar angle of (0,0)");
00362         }
00363     }
00364 
00365     double angle = atan(y/x);
00366 
00367     if (y >= 0 && x < 0 )
00368     {
00369         angle += M_PI;
00370     }
00371     else if (y < 0 && x < 0 )
00372     {
00373         angle -= M_PI;
00374     }
00375     return angle;
00376 };
00377 
00378 template<unsigned DIM>
00379 const VoronoiCell& VoronoiTessellation<DIM>::rGetCell(unsigned index) const
00380 {
00381     return mVoronoiCells[index];
00382 };
00383 
00384 template<unsigned DIM>
00385 const Face<DIM>* VoronoiTessellation<DIM>::GetFace(unsigned index) const
00386 {
00387     #define COVERAGE_IGNORE
00388     assert(DIM==2);
00389     #undef COVERAGE_IGNORE
00390 
00391     return mFaces[index];
00392 };
00393 
00394 template<unsigned DIM>
00395 double VoronoiTessellation<DIM>::GetEdgeLength(unsigned nodeIndex1, unsigned nodeIndex2) const
00396 {
00397     #define COVERAGE_IGNORE
00398     assert(DIM==2);
00399     #undef COVERAGE_IGNORE
00400 
00401     std::vector< c_vector<double, DIM>* > vertices_1 = mFaces[nodeIndex1]->mVertices;
00402     std::vector< c_vector<double, DIM>* > vertices_2 = mFaces[nodeIndex2]->mVertices;
00403     std::sort(vertices_1.begin(), vertices_1.end());
00404     std::sort(vertices_2.begin(), vertices_2.end());
00405     std::vector< c_vector<double, DIM>* > intersecting_vertices;
00406 
00407     set_intersection( vertices_1.begin(), vertices_1.end(),
00408                       vertices_2.begin(), vertices_2.end(),
00409                       back_inserter(intersecting_vertices) );
00410 #define COVERAGE_IGNORE //Debug code from r3223
00411     if (intersecting_vertices.size() != 2)
00412     {
00413         std::cout<< "node 1 = " << nodeIndex1 << " node 2 = " << nodeIndex2 <<" \n" << std::flush;
00414         std::cout<< "vertices 1 \n" << std::flush;
00415         for (unsigned i=0; i<vertices_1.size(); i++)
00416         {
00417             c_vector<double, DIM> current_vertex = *(vertices_1[i]);
00418             std::cout<<  current_vertex[0] << " \t" << current_vertex[1] << " \n" << std::flush;
00419         }
00420         std::cout<< "vertices 2 \n" << std::flush;
00421         for (unsigned i=0; i<vertices_2.size(); i++)
00422         {
00423             c_vector<double, DIM> current_vertex = *(vertices_2[i]);
00424             std::cout<<  current_vertex[0] << " \t" << current_vertex[1] << " \n" << std::flush;
00425         }
00426         std::cout<< "size of common vertices = " << intersecting_vertices.size() << " \n" << std::flush;
00427     }
00428 #undef COVERAGE_IGNORE
00429     assert(intersecting_vertices.size()==2);
00430 
00431     c_vector<double, DIM> edge_vector = mrMesh.GetVectorFromAtoB( *(intersecting_vertices[0]),
00432                                                                   *(intersecting_vertices[1]) );
00433 
00434     return norm_2(edge_vector);
00435 };
00436 
00437 template<unsigned DIM>
00438 double VoronoiTessellation<DIM>::GetFaceArea(unsigned index) const
00439 {
00440 #define COVERAGE_IGNORE
00441     assert(DIM==2);
00442 #undef COVERAGE_IGNORE
00443     Face<DIM>& face= *(mFaces[index]);
00444     assert(face.mVertices.size()>0);
00445 
00446     Face<DIM> normalised_face;
00447     std::vector< c_vector<double, DIM> > normalised_vertices;
00448     normalised_vertices.reserve(face.mVertices.size());
00449 
00450     c_vector<double, DIM> vertex = zero_vector<double>(DIM);
00451     normalised_vertices.push_back(vertex);
00452 
00453     normalised_face.mVertices.push_back( &(normalised_vertices[0]) );
00454 
00455     for (unsigned vertex_index=1; vertex_index<face.mVertices.size(); vertex_index++)
00456     {
00457         vertex = mrMesh.GetVectorFromAtoB( *(face.mVertices[0]),
00458                                            *(face.mVertices[vertex_index]) );
00459         normalised_vertices.push_back(vertex);
00460         normalised_face.mVertices.push_back( &(normalised_vertices.back()) );
00461     }
00462     normalised_face.OrderVerticesAntiClockwise();
00463 
00464     return normalised_face.GetArea();
00465 };
00466 
00467 template<unsigned DIM>
00468 double VoronoiTessellation<DIM>::GetFacePerimeter(unsigned index) const
00469 {
00470     #define COVERAGE_IGNORE
00471     assert(DIM==2);
00472     #undef COVERAGE_IGNORE
00473     Face<DIM>& face= *(mFaces[index]);
00474     assert(face.mVertices.size()>0);
00475 
00476     Face<DIM> normalised_face;
00477     std::vector< c_vector<double, DIM> > normalised_vertices;
00478     normalised_vertices.reserve(face.mVertices.size());
00479 
00480     c_vector<double, DIM> vertex = zero_vector<double>(DIM);
00481     normalised_vertices.push_back(vertex);
00482 
00483     normalised_face.mVertices.push_back( &(normalised_vertices[0]) );
00484 
00485     for (unsigned vertex_index=1; vertex_index<face.mVertices.size(); vertex_index++)
00486     {
00487         vertex = mrMesh.GetVectorFromAtoB( *(face.mVertices[0]),
00488                                            *(face.mVertices[vertex_index]) );
00489         normalised_vertices.push_back(vertex);
00490         normalised_face.mVertices.push_back( &(normalised_vertices.back()) );
00491     }
00492     normalised_face.OrderVerticesAntiClockwise();
00493 
00494     return normalised_face.GetPerimeter();
00495 
00496 };
00497 
00498 template<unsigned DIM>
00499 unsigned VoronoiTessellation<DIM>::GetNumVertices()
00500 {
00501     return mVertices.size();
00502 }
00503 
00504 template<unsigned DIM>
00505 unsigned VoronoiTessellation<DIM>::GetNumFaces()
00506 {
00507     return mFaces.size();
00508 }
00509 
00510 template<unsigned DIM>
00511 unsigned VoronoiTessellation<DIM>::GetNumCells()
00512 {
00513     assert(DIM==3);
00514     return mVoronoiCells.size();
00515 }
00516 
00517 template<unsigned DIM>
00518 c_vector<double,DIM>* VoronoiTessellation<DIM>::GetVertex(unsigned index)
00519 {
00520     assert(index<mVertices.size());
00521     return mVertices[index];
00522 }
00523 
00524 #endif /*VORONOITESSELLATION_HPP_*/

Generated on Wed Mar 18 12:51:56 2009 for Chaste by  doxygen 1.5.5