36 #include "VoronoiVertexMeshGenerator.hpp"
38 #if BOOST_VERSION >= 105200
40 using boost::polygon::voronoi_builder;
41 using boost::polygon::voronoi_diagram;
42 typedef boost::polygon::point_data<int> boost_point;
45 unsigned numElementsY,
46 unsigned numRelaxationSteps,
47 double elementTargetArea)
50 mNumElementsX(numElementsX),
51 mNumElementsY(numElementsY),
52 mNumRelaxationSteps(numRelaxationSteps),
53 mElementTargetArea(elementTargetArea),
55 mMaxExpectedNumSidesPerPolygon(17)
57 this->ValidateInputAndSetMembers();
58 this->GenerateVoronoiMesh();
61 VoronoiVertexMeshGenerator::~VoronoiVertexMeshGenerator()
73 void VoronoiVertexMeshGenerator::GenerateVoronoiMesh()
82 std::vector<c_vector<double, 2> > seed_locations = this->GetInitialPointLocations();
83 this->ValidateSeedLocations(seed_locations);
86 this->CreateVoronoiTessellation(seed_locations);
92 for (
unsigned relaxation = 0 ; relaxation < mNumRelaxationSteps ; relaxation++)
94 seed_locations.clear();
95 seed_locations = this->GetElementCentroidsFromMesh();
97 this->CreateVoronoiTessellation(seed_locations);
101 double scale_factor =
double(mMaxNumElems) * sqrt(mElementTargetArea);
102 for (
unsigned node_idx = 0 ; node_idx < mpMesh->GetNumNodes() ; node_idx++)
104 c_vector<double, 2>& node_location = mpMesh->GetNode(node_idx)->rGetModifiableLocation();
105 node_location *= scale_factor;
137 double width = mNumElementsX * sqrt(mElementTargetArea);
138 double height = mNumElementsY * sqrt(mElementTargetArea);
141 std::vector<Node<2>*> new_nodes(mpMesh->GetNumNodes());
142 std::vector<VertexElement<2,2>*> new_elems(mpMesh->GetNumElements());
145 for (
unsigned node_counter = 0 ; node_counter < mpMesh->GetNumNodes() ; node_counter++)
147 Node<2>* p_node_to_copy = mpMesh->GetNode(node_counter);
150 unsigned copy_index = p_node_to_copy->
GetIndex();
151 c_vector<double, 2> copy_location = p_node_to_copy->
rGetLocation();
155 assert(copy_index < mpMesh->GetNumNodes());
158 new_nodes[copy_index] =
new Node<2>(copy_index, copy_location, copy_is_boundary);
162 for (
unsigned elem_counter = 0; elem_counter < mpMesh->GetNumElements(); elem_counter++)
167 unsigned copy_index = p_elem_to_copy->
GetIndex();
168 unsigned copy_num_nodes = p_elem_to_copy->
GetNumNodes();
171 assert(copy_index < mpMesh->GetNumElements());
174 std::vector<Node<2>*> nodes_this_elem;
177 for (
unsigned node_local_idx = 0 ; node_local_idx < copy_num_nodes ; node_local_idx++)
180 unsigned local_node_global_idx = p_local_node->
GetIndex();
181 nodes_this_elem.push_back(new_nodes[local_node_global_idx]);
204 bool re_check =
true;
208 re_check = this->CheckForCongruentNodes(p_temp_mesh, width, height);
219 for (
unsigned node_counter = 0 ; node_counter < p_temp_mesh->
GetNumNodes() ; node_counter++)
224 unsigned copy_index = p_node_to_copy->
GetIndex();
225 c_vector<double, 2> copy_location = p_node_to_copy->
rGetLocation();
229 assert(!copy_is_boundary);
232 assert(copy_index < p_temp_mesh->GetNumNodes());
235 new_nodes[copy_index] =
new Node<2>(copy_index, copy_location,
false);
239 for (
unsigned elem_counter = 0; elem_counter < p_temp_mesh->
GetNumElements(); elem_counter++)
244 unsigned copy_index = p_elem_to_copy->
GetIndex();
245 unsigned copy_num_nodes = p_elem_to_copy->
GetNumNodes();
248 assert(copy_index < p_temp_mesh->GetNumElements());
251 std::vector<Node<2>*> nodes_this_elem;
254 for (
unsigned node_local_idx = 0 ; node_local_idx < copy_num_nodes ; node_local_idx++)
258 unsigned local_node_global_idx = p_local_node->
GetIndex();
260 nodes_this_elem.push_back(new_nodes[local_node_global_idx]);
277 c_vector<double, 2> min_x_y;
278 min_x_y[0] = DBL_MAX;
279 min_x_y[1] = DBL_MAX;
282 for (
unsigned node_idx = 0 ; node_idx < mpTorMesh->GetNumNodes() ; node_idx++)
284 c_vector<double, 2> this_node_location = mpTorMesh->GetNode(node_idx)->rGetLocation();
286 if(this_node_location[0] < min_x_y[0])
288 min_x_y[0] = this_node_location[0];
290 if(this_node_location[1] < min_x_y[1])
292 min_x_y[1] = this_node_location[1];
297 for (
unsigned node_idx = 0 ; node_idx < mpTorMesh->GetNumNodes() ; node_idx++)
299 mpTorMesh->GetNode(node_idx)->rGetModifiableLocation() -= min_x_y;
303 for (
unsigned node_idx = 0 ; node_idx < mpTorMesh->GetNumNodes() ; node_idx++)
305 if (mpTorMesh->GetNode(node_idx)->rGetLocation()[0] >= width)
307 mpTorMesh->GetNode(node_idx)->rGetModifiableLocation()[0] -= width;
309 if (mpTorMesh->GetNode(node_idx)->rGetLocation()[1] >= height)
311 mpTorMesh->GetNode(node_idx)->rGetModifiableLocation()[1] -= height;
318 bool VoronoiVertexMeshGenerator::CheckForCongruentNodes(
MutableVertexMesh<2,2>* pMesh,
double width,
double height)
321 std::vector<Node<2>*> boundary_nodes;
322 for (
unsigned node_idx = 0 ; node_idx < pMesh->
GetNumNodes() ; node_idx++)
328 boundary_nodes.push_back(p_node);
333 if (boundary_nodes.empty())
339 Node<2>* p_node_a = *(boundary_nodes.begin());
340 c_vector<double, 2> node_a_pos = p_node_a->
rGetLocation();
341 std::vector<c_vector<double,2> > congruent_locations(8, node_a_pos);
343 congruent_locations[0][0] += width;
345 congruent_locations[1][1] += height;
347 congruent_locations[2][0] -= width;
349 congruent_locations[3][1] -= height;
351 congruent_locations[4][0] += width;
352 congruent_locations[4][1] += height;
354 congruent_locations[5][0] -= width;
355 congruent_locations[5][1] += height;
357 congruent_locations[6][0] -= width;
358 congruent_locations[6][1] -= height;
360 congruent_locations[7][0] += width;
361 congruent_locations[7][1] -= height;
364 for (
unsigned node_b_counter = 0; node_b_counter < boundary_nodes.size(); node_b_counter++)
367 unsigned node_b_idx = boundary_nodes[node_b_counter]->GetIndex();
370 if (p_node_a == p_mesh_node_b)
375 c_vector<double, 2> node_b_pos = p_mesh_node_b->
rGetLocation();
378 for (
unsigned pos = 0 ; pos < congruent_locations.size() ; pos++)
380 if (norm_inf(node_b_pos - congruent_locations[pos]) < mTol)
385 assert(containing_elems.size() > 0);
387 for (std::set<unsigned>::iterator it = containing_elems.begin() ; it != containing_elems.end() ; ++it)
392 assert(local_idx < UINT_MAX);
394 p_this_elem->
AddNode(p_node_a, local_idx);
415 std::vector<c_vector<double, 2> > VoronoiVertexMeshGenerator::GetInitialPointLocations()
418 std::vector<c_vector<double, 2> > seed_points(mTotalNumElements);
423 for (
unsigned point_idx = 0 ; point_idx < mTotalNumElements ; point_idx++)
425 seed_points[point_idx][0] = p_rand_gen->
ranf() * mMultiplierInX;
426 seed_points[point_idx][1] = p_rand_gen->
ranf() * mMultiplierInY;
432 std::vector<c_vector<double, 2> > VoronoiVertexMeshGenerator::GetElementCentroidsFromMesh()
434 assert(mpMesh->GetNumElements() == mNumElementsX * mNumElementsY);
436 std::vector<c_vector<double, 2> > element_centroids;
439 for (
unsigned elem_idx = 0; elem_idx < mpMesh->GetNumElements(); elem_idx++)
442 c_vector<double, 2> this_centroid = mpMesh->GetCentroidOfElement(elem_idx);
451 if (this_centroid[0] < 0.0)
453 this_centroid[0] += mMultiplierInX;
455 else if (this_centroid[0] > mMultiplierInX)
457 this_centroid[0] -= mMultiplierInX;
461 if (this_centroid[1] < 0.0)
463 this_centroid[1] += mMultiplierInY;
465 else if (this_centroid[1] > mMultiplierInY)
467 this_centroid[1] -= mMultiplierInY;
470 element_centroids.push_back(this_centroid);
473 return element_centroids;
476 void VoronoiVertexMeshGenerator::CreateVoronoiTessellation(std::vector<c_vector<double, 2> >& rSeedLocations)
479 std::vector<Node<2>*> nodes;
480 std::vector<VertexElement<2, 2>* > elements;
490 std::vector<boost_point> points;
493 for (
unsigned point_idx = 0 ; point_idx < rSeedLocations.size() ; point_idx++)
496 int point_x = int( floor( (rSeedLocations[point_idx][0] * mSamplingMultiplier) + 0.5) );
497 int point_y = int( floor( (rSeedLocations[point_idx][1] * mSamplingMultiplier) + 0.5) );
499 points.push_back( boost_point(point_x, point_y) );
503 std::vector<boost_point> offsets;
504 offsets.push_back( boost_point(-mMaxIntX, mMaxIntY) );
505 offsets.push_back( boost_point( 0, mMaxIntY) );
506 offsets.push_back( boost_point( mMaxIntX, mMaxIntY) );
507 offsets.push_back( boost_point( mMaxIntX, 0) );
508 offsets.push_back( boost_point( mMaxIntX, -mMaxIntY) );
509 offsets.push_back( boost_point( 0, -mMaxIntY) );
510 offsets.push_back( boost_point(-mMaxIntX, -mMaxIntY) );
511 offsets.push_back( boost_point(-mMaxIntX, 0) );
515 for (
unsigned rep = 0; rep < offsets.size(); rep++)
517 boost_point offset = offsets[rep];
518 for (
unsigned point_idx = 0; point_idx < rSeedLocations.size(); point_idx++)
520 boost_point new_point = boost_point(points[point_idx].x() + offset.x(), points[point_idx].y() + offset.y());
521 points.push_back(new_point);
541 voronoi_diagram<double> vd;
542 construct_voronoi(points.begin(), points.end(), &vd);
545 for (voronoi_diagram<double>::const_cell_iterator it = vd.cells().begin();
546 it != vd.cells().end();
550 const voronoi_diagram<double>::cell_type& cell = *it;
554 if (cell.source_index() < rSeedLocations.size())
557 std::vector<Node<2>*> nodes_this_elem;
560 const voronoi_diagram<double>::edge_type *edge = cell.incident_edge();
564 if (edge->is_primary())
567 double x_location = (edge->vertex0()->x()) / mSamplingMultiplier;
568 double y_location = (edge->vertex0()->y()) / mSamplingMultiplier;
571 Node<2>* p_this_node =
new Node<2>(nodes.size(),
false, x_location, y_location);
580 unsigned existing_node_idx = UINT_MAX;
582 for (
unsigned node_idx = 0; node_idx < nodes.size(); node_idx++)
585 c_vector<double, 2> existing_node_location = nodes[node_idx]->
rGetLocation();
588 if ( fabs(existing_node_location[0] - p_this_node->
rGetLocation()[0]) < DBL_EPSILON )
590 if ( fabs(existing_node_location[1] - p_this_node->
rGetLocation()[1]) < DBL_EPSILON )
593 existing_node_idx = node_idx;
598 if (existing_node_idx < UINT_MAX)
601 nodes_this_elem.push_back(nodes[existing_node_idx]);
607 nodes.push_back(p_this_node);
608 nodes_this_elem.push_back(p_this_node);
615 }
while (edge != cell.incident_edge());
623 for (voronoi_diagram<double>::const_cell_iterator it = vd.cells().begin();
624 it != vd.cells().end();
628 const voronoi_diagram<double>::cell_type& cell = *it;
632 if (cell.source_index() >= rSeedLocations.size())
635 const voronoi_diagram<double>::edge_type *edge = cell.incident_edge();
642 if (edge->is_infinite())
647 if (edge->is_primary())
649 c_vector<double, 2> vertex_location;
652 vertex_location[0] = (edge->vertex0()->x()) / mSamplingMultiplier;
653 vertex_location[1] = (edge->vertex0()->y()) / mSamplingMultiplier;
659 for (
unsigned node_idx = 0 ; node_idx < nodes.size() ; node_idx++)
662 c_vector<double, 2> existing_node_location = nodes[node_idx]->
rGetLocation();
665 if ( fabs(existing_node_location[0] - vertex_location[0]) < DBL_EPSILON )
667 if ( fabs(existing_node_location[1] - vertex_location[1]) < DBL_EPSILON )
670 nodes[node_idx]->SetAsBoundaryNode(
true);
678 }
while (edge != cell.incident_edge());
690 void VoronoiVertexMeshGenerator::ValidateInputAndSetMembers()
693 if ( (mNumElementsX < 2) || (mNumElementsY < 2) )
698 if ( mElementTargetArea <= 0.0 )
700 EXCEPTION(
"Specified target area must be strictly positive");
704 mTotalNumElements = mNumElementsX * mNumElementsY;
707 mMaxNumElems = std::max(mNumElementsX, mNumElementsY);
710 mMultiplierInX =
double(mNumElementsX) /
double(mMaxNumElems);
711 mMultiplierInY =
double(mNumElementsY) /
double(mMaxNumElems);
714 mSamplingMultiplier = 0.5 *
double(INT_MAX);
717 mMaxIntX = int( floor( (mMultiplierInX * mSamplingMultiplier) + 0.5 ) );
718 mMaxIntY = int( floor( (mMultiplierInY * mSamplingMultiplier) + 0.5 ) );
721 void VoronoiVertexMeshGenerator::ValidateSeedLocations(std::vector<c_vector<double, 2> >& rSeedLocations)
723 unsigned num_seeds = rSeedLocations.size();
730 double safe_distance = 1.5 / mSamplingMultiplier;
741 for (
unsigned seed_idx_one = 0; seed_idx_one < num_seeds; seed_idx_one++)
743 for (
unsigned seed_idx_two = seed_idx_one + 1; seed_idx_two < num_seeds; seed_idx_two++)
746 c_vector<double, 2> one_to_two = rSeedLocations[seed_idx_two] - rSeedLocations[seed_idx_one];
747 double distance = norm_2(one_to_two);
749 if (distance < safe_distance)
761 if (distance > DBL_EPSILON)
763 double multiplier = safe_distance / distance;
764 rSeedLocations[seed_idx_two] += (one_to_two * multiplier);
766 rSeedLocations[seed_idx_two][0] = fmod(rSeedLocations[seed_idx_two][0] + mMultiplierInX, mMultiplierInX);
767 rSeedLocations[seed_idx_two][1] = fmod(rSeedLocations[seed_idx_two][1] + mMultiplierInX, mMultiplierInX);
771 rSeedLocations[seed_idx_two][0] += safe_distance;
772 rSeedLocations[seed_idx_two][0] = fmod(rSeedLocations[seed_idx_two][0], mMultiplierInX);
786 std::vector<double> VoronoiVertexMeshGenerator::GetPolygonDistribution()
788 assert(mpMesh != NULL);
791 unsigned num_elems = mpMesh->GetNumElements();
794 std::vector<unsigned> num_polygons(mMaxExpectedNumSidesPerPolygon - 2, 0);
797 std::vector<double> polygon_dist;
800 for (
unsigned elem_idx = 0; elem_idx < num_elems; elem_idx++)
802 unsigned num_nodes_this_elem = mpMesh->GetElement(elem_idx)->GetNumNodes();
805 assert(num_nodes_this_elem > 2);
806 assert(num_nodes_this_elem <= mMaxExpectedNumSidesPerPolygon);
809 num_polygons[num_nodes_this_elem - 3]++;
813 unsigned elems_accounted_for = 0;
814 for (
unsigned polygon = 0 ; polygon < num_polygons.size() ; polygon++)
816 elems_accounted_for += num_polygons[polygon];
818 polygon_dist.push_back(static_cast<double>(num_polygons[polygon]) / static_cast<double>(num_elems));
821 if (elems_accounted_for == num_elems)
830 double VoronoiVertexMeshGenerator::GetAreaCoefficientOfVariation()
832 assert(mpMesh != NULL);
835 unsigned num_elems = mpMesh->GetNumElements();
836 assert(num_elems > 1);
841 for (
unsigned elem_idx = 0 ; elem_idx < num_elems ; elem_idx++)
843 double deviation = mpMesh->GetVolumeOfElement(elem_idx) - mElementTargetArea;
844 var += deviation * deviation;
847 var /=
static_cast<double>(num_elems - 1);
849 return sqrt(var) / mElementTargetArea;
852 void VoronoiVertexMeshGenerator::RefreshSeedsAndRegenerateMesh()
854 this->GenerateVoronoiMesh();
857 void VoronoiVertexMeshGenerator::SetMaxExpectedNumSidesPerPolygon(
unsigned maxExpectedNumSidesPerPolygon)
859 mMaxExpectedNumSidesPerPolygon = maxExpectedNumSidesPerPolygon;
862 unsigned VoronoiVertexMeshGenerator::GetMaxExpectedNumSidesPerPolygon()
864 return mMaxExpectedNumSidesPerPolygon;
867 #endif // BOOST_VERSION >= 105200
868 #if BOOST_VERSION < 105200
876 EXCEPTION(
"This is a dummy class. Build with Boost version 1.52 or above for functionality.");
879 #endif // BOOST_VERSION < 105200
void SetAsBoundaryNode(bool value=true)
bool IsBoundaryNode() const
Node< SPACE_DIM > * GetNode(unsigned index) const
#define EXCEPTION(message)
std::set< unsigned > & rGetContainingElementIndices()
VertexElement< ELEMENT_DIM, SPACE_DIM > * GetElement(unsigned index) const
VoronoiVertexMeshGenerator()
Node< SPACE_DIM > * GetNode(unsigned localIndex) const
void AddNode(Node< SPACE_DIM > *pNode, const unsigned &rIndex)
unsigned GetNumNodes() const
unsigned GetNumNodes() const
void DeleteNodePriorToReMesh(unsigned index)
static RandomNumberGenerator * Instance()
virtual void ReMesh(VertexElementMap &rElementMap)
const c_vector< double, SPACE_DIM > & rGetLocation() const
unsigned GetIndex() const
unsigned GetNumElements() const
void RemoveDeletedNodes()
void DeleteNode(const unsigned &rIndex)
unsigned GetIndex() const
unsigned GetNodeLocalIndex(unsigned globalIndex) const