VoronoiTessellation.cpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2010
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 #include "VoronoiTessellation.hpp"
00031 #include <list>
00032 
00037 template<unsigned DIM>
00038 bool VertexAngleComparison(const std::pair<c_vector<double, DIM>*, double> lhs, const std::pair<c_vector<double, DIM>*, double> rhs)
00039 {
00040     return lhs.second < rhs.second;
00041 }
00042 
00044 // Implementation
00046 
00047 template<unsigned DIM>
00048 VoronoiTessellation<DIM>::VoronoiTessellation(TetrahedralMesh<DIM,DIM>& rMesh, const std::vector<unsigned> locationIndices)
00049     : mrMesh(rMesh)
00050 {
00051     #define COVERAGE_IGNORE
00052     assert(DIM==2 || DIM==3);
00053     #undef COVERAGE_IGNORE
00054 
00055     if (!locationIndices.empty())
00056     {
00057         for (unsigned i=0; i<locationIndices.size(); i++)
00058         {
00059             mLocationIndices.insert(locationIndices[i]);
00060         }
00061     }
00062 
00063     Initialise(rMesh);
00064 }
00065 
00071 template<>
00072 void VoronoiTessellation<1>::Initialise(TetrahedralMesh<1,1>& rMesh)
00073 {
00074     // No 1D Voronoi tessellation
00075     NEVER_REACHED;
00076 }
00077 
00083 template<>
00084 void VoronoiTessellation<2>::Initialise(TetrahedralMesh<2,2>& rMesh)
00085 {
00086     // Populate mVertices with element circumcentres
00087     GenerateVerticesFromElementCircumcentres();
00088 
00089     // Create as many Faces as there are nodes in the mesh
00090     for (unsigned i=0; i<rMesh.GetNumAllNodes(); i++)
00091     {
00092         Face<2>* p_face = new Face<2>;
00093         mFaces.push_back(p_face);
00094     }
00095 
00096     // Add mVertices to mFaces by looping over the edges of each element in the mesh
00097     for (unsigned i=0; i<mrMesh.GetNumElements(); i++)
00098     {
00099         for (unsigned node_index=0; node_index<3; node_index++)
00100         {
00101             unsigned node_global_index = mrMesh.GetElement(i)->GetNodeGlobalIndex(node_index);
00102 
00103             if (!mLocationIndices.empty())
00104             {
00105                 if (mLocationIndices.find(node_global_index) != mLocationIndices.end())
00106                 {
00107                     mFaces[node_global_index]->AddVertex(mVertices[i]);
00108                 }
00109             }
00110             else
00111             {
00112                 mFaces[node_global_index]->AddVertex(mVertices[i]);
00113             }
00114         }
00115     }
00116 
00117     // Reorder mVertices Anticlockwise
00118     for (unsigned i=0; i<mFaces.size(); i++)
00119     {
00120         // Compute and store the polar angle from the centre to each vertex
00121         std::list<std::pair<c_vector<double, 2>*, double> > vertex_angle_list;
00122         for (unsigned j=0; j<mFaces[i]->GetNumVertices(); j++)
00123         {
00124             c_vector<double, 2> centre_to_vertex = mFaces[i]->rGetVertex(j) - mrMesh.GetNode(i)->rGetLocation();
00125             double angle = atan2(centre_to_vertex(1), centre_to_vertex(0));
00126             std::pair<c_vector<double, 2>*, double> pair(&(mFaces[i]->rGetVertex(j)), angle);
00127             vertex_angle_list.push_back(pair);
00128         }
00129 
00130         // Sort the list in order of increasing angle
00131         vertex_angle_list.sort(VertexAngleComparison<2>);
00132 
00133         // Create face
00134         Face<2>* p_face = new Face<2>;
00135         for (std::list<std::pair<c_vector<double, 2>*, double> >::iterator list_iter = vertex_angle_list.begin();
00136              list_iter != vertex_angle_list.end();
00137              ++list_iter)
00138         {
00139             p_face->AddVertex(list_iter->first);
00140         }
00141 
00142         // Add face to list of faces
00143         delete mFaces[i];
00144         mFaces[i] = p_face;
00145     }
00146 }
00147 
00153 template<>
00154 void VoronoiTessellation<3>::Initialise(TetrahedralMesh<3,3>& rMesh)
00155 {
00156     // Populate mVertices with element circumcentres
00157     GenerateVerticesFromElementCircumcentres();
00158 
00159     // Allocate memory for mVoronoiCells
00160     mVoronoiCells.resize(rMesh.GetNumAllNodes());
00161 
00162     // Loop over each edge
00163     for (TetrahedralMesh<3,3>::EdgeIterator edge_iterator = mrMesh.EdgesBegin();
00164          edge_iterator != mrMesh.EdgesEnd();
00165          ++edge_iterator)
00166     {
00167         Node<3>* p_node_a = edge_iterator.GetNodeA();
00168         Node<3>* p_node_b = edge_iterator.GetNodeB();
00169 
00170         if ( p_node_a->IsBoundaryNode() && p_node_b->IsBoundaryNode() )
00171         {
00172             // This edge is on the boundary
00173             Face<3>* p_null_face = new Face<3>;
00174             mFaces.push_back(p_null_face);
00175         }
00176         else
00177         {
00178             std::set<unsigned>& node_a_element_indices = p_node_a->rGetContainingElementIndices();
00179             std::set<unsigned>& node_b_element_indices = p_node_b->rGetContainingElementIndices();
00180             std::set<unsigned> edge_element_indices;
00181 
00182             std::set_intersection(node_a_element_indices.begin(),
00183                                   node_a_element_indices.end(),
00184                                   node_b_element_indices.begin(),
00185                                   node_b_element_indices.end(),
00186                                   std::inserter(edge_element_indices, edge_element_indices.begin()));
00187 
00188             c_vector<double,3> edge_vector = p_node_b->rGetLocation() - p_node_a->rGetLocation();
00189             c_vector<double,3> mid_edge = edge_vector*0.5 + p_node_a->rGetLocation();
00190 
00191             unsigned element0_index = *(edge_element_indices.begin());
00192 
00193             c_vector<double,3> basis_vector1 = *(mVertices[element0_index]) - mid_edge;
00194 
00195             c_vector<double,3> basis_vector2;
00196             basis_vector2[0] = edge_vector[1]*basis_vector1[2] - edge_vector[2]*basis_vector1[1];
00197             basis_vector2[1] = edge_vector[2]*basis_vector1[0] - edge_vector[0]*basis_vector1[2];
00198             basis_vector2[2] = edge_vector[0]*basis_vector1[1] - edge_vector[1]*basis_vector1[0];
00199 
00200             std::list<std::pair<c_vector<double, 3>*, double> > vertex_angle_list;
00201 
00202             // Loop over each element containing this edge:
00203             // the elements are those containing both nodes of the edge
00204             for (std::set<unsigned>::iterator element_index_iterator = edge_element_indices.begin();
00205                  element_index_iterator != edge_element_indices.end();
00206                  element_index_iterator++)
00207             {
00208                 // Calculate angle
00209                 c_vector<double, 3> vertex_vector = *(mVertices[*element_index_iterator]) - mid_edge;
00210     
00211                 double local_vertex_dot_basis_vector1 = inner_prod(vertex_vector, basis_vector1);
00212                 double local_vertex_dot_basis_vector2 = inner_prod(vertex_vector, basis_vector2);
00213 
00214                 double angle = atan2(local_vertex_dot_basis_vector2, local_vertex_dot_basis_vector1);
00215 
00216                 std::pair<c_vector<double, 3>*, double> pair(mVertices[*element_index_iterator], angle);
00217                 vertex_angle_list.push_back(pair);
00218             }
00219 
00220             // Sort the list in order of increasing angle
00221             vertex_angle_list.sort(VertexAngleComparison<3>);
00222 
00223             // Create face
00224             Face<3>* p_face = new Face<3>;
00225             for (std::list<std::pair<c_vector<double, 3>*, double> >::iterator list_iter = vertex_angle_list.begin();
00226                  list_iter != vertex_angle_list.end();
00227                  ++list_iter)
00228             {
00229                 p_face->AddVertex(list_iter->first);
00230             }
00231 
00232             // Add face to list of faces...
00233             mFaces.push_back(p_face);
00234 
00235             // ...and appropriate elements
00236             if (!p_node_a->IsBoundaryNode())
00237             {
00238                 mVoronoiCells[p_node_a->GetIndex()].AddFace(p_face);
00239                 mVoronoiCells[p_node_a->GetIndex()].AddOrientation(true);
00240                 mVoronoiCells[p_node_a->GetIndex()].SetCellCentre(p_node_a->rGetLocation());
00241             }
00242             if (!p_node_b->IsBoundaryNode())
00243             {
00244                 mVoronoiCells[p_node_b->GetIndex()].AddFace(p_face);
00245                 mVoronoiCells[p_node_b->GetIndex()].AddOrientation(false);
00246                 mVoronoiCells[p_node_b->GetIndex()].SetCellCentre(p_node_b->rGetLocation());
00247             }
00248         }
00249     }
00250 }
00251 
00252 template<unsigned DIM>
00253 VoronoiTessellation<DIM>::~VoronoiTessellation()
00254 {
00255     // Delete faces
00256     for (typename std::vector< Face<DIM>* >::iterator face_iterator = mFaces.begin();
00257          face_iterator != mFaces.end();
00258          face_iterator++)
00259     {
00260         delete *face_iterator;
00261     }
00262     // Delete vertices
00263     for (typename std::vector< c_vector<double,DIM>* >::iterator vertex_iterator = mVertices.begin();
00264          vertex_iterator != mVertices.end();
00265          vertex_iterator++)
00266     {
00267         delete *vertex_iterator;
00268     }
00269 }
00270 
00271 template<unsigned DIM>
00272 void VoronoiTessellation<DIM>::GenerateVerticesFromElementCircumcentres()
00273 {
00274     c_matrix<double, DIM, DIM> jacobian, inverse_jacobian;
00275     double jacobian_det;
00276     for (unsigned i=0; i<mrMesh.GetNumElements(); i++)
00277     {
00278         mrMesh.GetInverseJacobianForElement(i, jacobian, jacobian_det, inverse_jacobian);
00279 
00280         c_vector<double,DIM+1> circumsphere = mrMesh.GetElement(i)->CalculateCircumsphere(jacobian, inverse_jacobian);
00281 
00282         c_vector<double,DIM>*  p_circumcentre = new c_vector<double, DIM>;
00283         for (unsigned j=0; j<DIM; j++)
00284         {
00285             (*p_circumcentre)(j)=circumsphere(j);
00286         }
00287         mVertices.push_back(p_circumcentre);
00288     }
00289 }
00290 
00291 template<unsigned DIM>
00292 const VoronoiCell& VoronoiTessellation<DIM>::rGetCell(unsigned index) const
00293 {
00294     #define COVERAGE_IGNORE
00295     assert(DIM==3);
00296     #undef COVERAGE_IGNORE
00297 
00298     return mVoronoiCells[index];
00299 }
00300 
00301 template<unsigned DIM>
00302 const Face<DIM>& VoronoiTessellation<DIM>::rGetFace(unsigned index) const
00303 {
00304     #define COVERAGE_IGNORE
00305     assert(DIM==2);
00306     #undef COVERAGE_IGNORE
00307 
00308     if (!mLocationIndices.empty())
00309     {
00310         if (mLocationIndices.find(index) == mLocationIndices.end())
00311         {
00312             EXCEPTION("Attempting to get a Face corresponding to a ghost node");
00313         }
00314     }
00315 
00316     return *(mFaces[index]);
00317 }
00318 
00319 template<unsigned DIM>
00320 double VoronoiTessellation<DIM>::GetEdgeLength(unsigned nodeIndex1, unsigned nodeIndex2) const
00321 {
00322     #define COVERAGE_IGNORE
00323     assert(DIM==2);
00324     #undef COVERAGE_IGNORE
00325 
00326     if (!mLocationIndices.empty())
00327     {
00328         if (   mLocationIndices.find(nodeIndex1) == mLocationIndices.end()
00329             || mLocationIndices.find(nodeIndex2) == mLocationIndices.end() )
00330         {
00331             EXCEPTION("Attempting to get the tessellation edge between two nodes, at least one of which is a ghost node");
00332         }
00333     }
00334 
00335     std::vector< c_vector<double, DIM>* > vertices_1;
00336     for (unsigned i=0; i<mFaces[nodeIndex1]->GetNumVertices(); i++)
00337     {
00338         vertices_1.push_back(&(mFaces[nodeIndex1]->rGetVertex(i)));
00339     }
00340     std::vector< c_vector<double, DIM>* > vertices_2;
00341     for (unsigned i=0; i<mFaces[nodeIndex2]->GetNumVertices(); i++)
00342     {
00343         vertices_2.push_back(&(mFaces[nodeIndex2]->rGetVertex(i)));
00344     }
00345 
00346     std::sort(vertices_1.begin(), vertices_1.end());
00347     std::sort(vertices_2.begin(), vertices_2.end());
00348     std::vector< c_vector<double, DIM>* > intersecting_vertices;
00349 
00350     set_intersection( vertices_1.begin(), vertices_1.end(),
00351                       vertices_2.begin(), vertices_2.end(),
00352                       back_inserter(intersecting_vertices) );
00353 
00354 #define COVERAGE_IGNORE //Debug code from r3223
00355     if (intersecting_vertices.size() != 2)
00356     {
00357         std::cout << "node 1 = " << nodeIndex1 << " node 2 = " << nodeIndex2 << " \n" << std::flush;
00358         std::cout << "vertices 1 \n" << std::flush;
00359         for (unsigned i=0; i<vertices_1.size(); i++)
00360         {
00361             c_vector<double, DIM> current_vertex = *(vertices_1[i]);
00362             std::cout << current_vertex[0] << " \t" << current_vertex[1] << " \n" << std::flush;
00363         }
00364         std::cout << "vertices 2 \n" << std::flush;
00365         for (unsigned i=0; i<vertices_2.size(); i++)
00366         {
00367             c_vector<double, DIM> current_vertex = *(vertices_2[i]);
00368             std::cout << current_vertex[0] << " \t" << current_vertex[1] << " \n" << std::flush;
00369         }
00370         std::cout << "size of common vertices = " << intersecting_vertices.size() << " \n" << std::flush;
00371     }
00372 #undef COVERAGE_IGNORE
00373     assert(intersecting_vertices.size()==2);
00374 
00375     c_vector<double, DIM> edge_vector = mrMesh.GetVectorFromAtoB( *(intersecting_vertices[0]),
00376                                                                   *(intersecting_vertices[1]) );
00377 
00378     return norm_2(edge_vector);
00379 }
00380 
00381 template<unsigned DIM>
00382 double VoronoiTessellation<DIM>::GetFaceArea(unsigned index) const
00383 {
00384     #define COVERAGE_IGNORE
00385     assert(DIM==2);
00386     #undef COVERAGE_IGNORE
00387 
00388     if (!mLocationIndices.empty())
00389     {
00390         if (mLocationIndices.find(index) == mLocationIndices.end())
00391         {
00392             EXCEPTION("Attempting to get the area of a Face corresponding to a ghost node");
00393         }
00394     }
00395 
00396     Face<DIM>& face = *(mFaces[index]);
00397     assert(face.GetNumVertices() > 0);
00398 
00399     Face<DIM> normalised_face;
00400     std::vector< c_vector<double, DIM> > normalised_vertices;
00401     normalised_vertices.reserve(face.GetNumVertices());
00402 
00403     c_vector<double, DIM> vertex = zero_vector<double>(DIM);
00404     normalised_vertices.push_back(vertex);
00405 
00406     normalised_face.AddVertex( &(normalised_vertices[0]) );
00407 
00408     for (unsigned vertex_index=1; vertex_index<face.GetNumVertices(); vertex_index++)
00409     {
00410         vertex = mrMesh.GetVectorFromAtoB(face.rGetVertex(0), face.rGetVertex(vertex_index));
00411         normalised_vertices.push_back(vertex);
00412         normalised_face.AddVertex( &(normalised_vertices.back()) );
00413     }
00414     normalised_face.OrderVerticesAntiClockwise();
00415 
00416     double normalised_face_area = 0;
00417     for (unsigned i=0; i<normalised_face.GetNumVertices(); i++)
00418     {
00419         /*
00420          * Area = sum ( x_i * y_i+1 - y_i * x_i+1 )/2.0 over all vertices,
00421          * assuming vertices are ordered anti-clockwise.
00422          */
00423         c_vector<double, DIM> this_vertex = normalised_face.rGetVertex(i);
00424         c_vector<double, DIM> next_vertex =  normalised_face.rGetVertex((i+1)%normalised_face.GetNumVertices());
00425 
00426         normalised_face_area += 0.5*( this_vertex(0)*next_vertex(1) - this_vertex(1)*next_vertex(0) );
00427     }
00428     return normalised_face_area;
00429 }
00430 
00431 template<unsigned DIM>
00432 double VoronoiTessellation<DIM>::GetFacePerimeter(unsigned index) const
00433 {
00434     #define COVERAGE_IGNORE
00435     assert(DIM==2);
00436     #undef COVERAGE_IGNORE
00437 
00438     if (!mLocationIndices.empty())
00439     {
00440         if (mLocationIndices.find(index) == mLocationIndices.end())
00441         {
00442             EXCEPTION("Attempting to get the perimeter of a Face corresponding to a ghost node");
00443         }
00444     }
00445 
00446     Face<DIM>& face = *(mFaces[index]);
00447     assert(face.GetNumVertices() > 0);
00448 
00449     Face<DIM> normalised_face;
00450     std::vector< c_vector<double, DIM> > normalised_vertices;
00451     normalised_vertices.reserve(face.GetNumVertices());
00452 
00453     c_vector<double, DIM> vertex = zero_vector<double>(DIM);
00454     normalised_vertices.push_back(vertex);
00455 
00456     normalised_face.AddVertex( &(normalised_vertices[0]) );
00457 
00458     for (unsigned vertex_index=1; vertex_index<face.GetNumVertices(); vertex_index++)
00459     {
00460         vertex = mrMesh.GetVectorFromAtoB(face.rGetVertex(0), face.rGetVertex(vertex_index));
00461         normalised_vertices.push_back(vertex);
00462         normalised_face.AddVertex( &(normalised_vertices.back()) );
00463     }
00464     normalised_face.OrderVerticesAntiClockwise();
00465 
00466     double normalised_face_perimeter = 0;
00467     for (unsigned i=0; i<normalised_face.GetNumVertices(); i++)
00468     {
00469         c_vector<double, DIM> this_vertex = normalised_face.rGetVertex(i);
00470         c_vector<double, DIM> next_vertex =  normalised_face.rGetVertex((i+1)%normalised_face.GetNumVertices());
00471 
00472         normalised_face_perimeter += norm_2(this_vertex - next_vertex);
00473     }
00474     return normalised_face_perimeter;
00475 }
00476 
00477 template<unsigned DIM>
00478 unsigned VoronoiTessellation<DIM>::GetNumVertices() const
00479 {
00480     return mVertices.size();
00481 }
00482 
00483 template<unsigned DIM>
00484 unsigned VoronoiTessellation<DIM>::GetNumFaces() const
00485 {
00487     return mFaces.size();
00488 }
00489 
00490 template<unsigned DIM>
00491 unsigned VoronoiTessellation<DIM>::GetNumCells()
00492 {
00493     assert(DIM==3);
00494     return mVoronoiCells.size();
00495 }
00496 
00497 template<unsigned DIM>
00498 c_vector<double,DIM>* VoronoiTessellation<DIM>::GetVertex(unsigned index)
00499 {
00500     assert(index<mVertices.size());
00501     return mVertices[index];
00502 }
00503 
00504 
00506 // Explicit instantiation
00508 
00509 
00510 template class VoronoiTessellation<1>;
00511 template class VoronoiTessellation<2>;
00512 template class VoronoiTessellation<3>;

Generated by  doxygen 1.6.2