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();
152 const 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 const c_vector<double, 2>& copy_location = p_node_to_copy->
rGetLocation();
231 assert(copy_index < p_temp_mesh->GetNumNodes());
234 new_nodes[copy_index] =
new Node<2>(copy_index, copy_location,
false);
238 for (
unsigned elem_counter = 0; elem_counter < p_temp_mesh->
GetNumElements(); elem_counter++)
243 unsigned copy_index = p_elem_to_copy->
GetIndex();
244 unsigned copy_num_nodes = p_elem_to_copy->
GetNumNodes();
247 assert(copy_index < p_temp_mesh->GetNumElements());
250 std::vector<Node<2>*> nodes_this_elem;
253 for (
unsigned node_local_idx = 0 ; node_local_idx < copy_num_nodes ; node_local_idx++)
257 unsigned local_node_global_idx = p_local_node->
GetIndex();
259 nodes_this_elem.push_back(new_nodes[local_node_global_idx]);
276 c_vector<double, 2> min_x_y;
277 min_x_y[0] = DBL_MAX;
278 min_x_y[1] = DBL_MAX;
281 for (
unsigned node_idx = 0 ; node_idx < mpTorMesh->GetNumNodes() ; node_idx++)
283 const c_vector<double, 2>& r_this_node_location = mpTorMesh->GetNode(node_idx)->rGetLocation();
285 if (r_this_node_location[0] < min_x_y[0])
287 min_x_y[0] = r_this_node_location[0];
289 if (r_this_node_location[1] < min_x_y[1])
291 min_x_y[1] = r_this_node_location[1];
296 for (
unsigned node_idx = 0 ; node_idx < mpTorMesh->GetNumNodes() ; node_idx++)
298 mpTorMesh->GetNode(node_idx)->rGetModifiableLocation() -= min_x_y;
302 for (
unsigned node_idx = 0 ; node_idx < mpTorMesh->GetNumNodes() ; node_idx++)
304 if (mpTorMesh->GetNode(node_idx)->rGetLocation()[0] >= width)
306 mpTorMesh->GetNode(node_idx)->rGetModifiableLocation()[0] -= width;
308 if (mpTorMesh->GetNode(node_idx)->rGetLocation()[1] >= height)
310 mpTorMesh->GetNode(node_idx)->rGetModifiableLocation()[1] -= height;
317 bool VoronoiVertexMeshGenerator::CheckForCongruentNodes(
MutableVertexMesh<2,2>* pMesh,
double width,
double height)
320 std::vector<Node<2>*> boundary_nodes;
321 for (
unsigned node_idx = 0 ; node_idx < pMesh->
GetNumNodes() ; node_idx++)
327 boundary_nodes.push_back(p_node);
332 if (boundary_nodes.empty())
338 Node<2>* p_node_a = *(boundary_nodes.begin());
339 c_vector<double, 2> node_a_pos = p_node_a->
rGetLocation();
340 std::vector<c_vector<double,2> > congruent_locations(8, node_a_pos);
342 congruent_locations[0][0] += width;
344 congruent_locations[1][1] += height;
346 congruent_locations[2][0] -= width;
348 congruent_locations[3][1] -= height;
350 congruent_locations[4][0] += width;
351 congruent_locations[4][1] += height;
353 congruent_locations[5][0] -= width;
354 congruent_locations[5][1] += height;
356 congruent_locations[6][0] -= width;
357 congruent_locations[6][1] -= height;
359 congruent_locations[7][0] += width;
360 congruent_locations[7][1] -= height;
363 for (
unsigned node_b_counter = 0; node_b_counter < boundary_nodes.size(); node_b_counter++)
366 unsigned node_b_idx = boundary_nodes[node_b_counter]->GetIndex();
369 if (p_node_a == p_mesh_node_b)
374 c_vector<double, 2> node_b_pos = p_mesh_node_b->
rGetLocation();
377 for (
unsigned pos = 0 ; pos < congruent_locations.size() ; pos++)
379 if (norm_inf(node_b_pos - congruent_locations[pos]) < mTol)
384 assert(containing_elems.size() > 0);
386 for (std::set<unsigned>::iterator it = containing_elems.begin() ; it != containing_elems.end() ; ++it)
391 assert(local_idx < UINT_MAX);
393 p_this_elem->
AddNode(p_node_a, local_idx);
414 std::vector<c_vector<double, 2> > VoronoiVertexMeshGenerator::GetInitialPointLocations()
417 std::vector<c_vector<double, 2> > seed_points(mTotalNumElements);
422 for (
unsigned point_idx = 0 ; point_idx < mTotalNumElements ; point_idx++)
424 seed_points[point_idx][0] = p_rand_gen->
ranf() * mMultiplierInX;
425 seed_points[point_idx][1] = p_rand_gen->
ranf() * mMultiplierInY;
431 std::vector<c_vector<double, 2> > VoronoiVertexMeshGenerator::GetElementCentroidsFromMesh()
433 assert(mpMesh->GetNumElements() == mNumElementsX * mNumElementsY);
435 std::vector<c_vector<double, 2> > element_centroids;
438 for (
unsigned elem_idx = 0; elem_idx < mpMesh->GetNumElements(); elem_idx++)
441 c_vector<double, 2> this_centroid = mpMesh->GetCentroidOfElement(elem_idx);
450 if (this_centroid[0] < 0.0)
452 this_centroid[0] += mMultiplierInX;
454 else if (this_centroid[0] > mMultiplierInX)
456 this_centroid[0] -= mMultiplierInX;
460 if (this_centroid[1] < 0.0)
462 this_centroid[1] += mMultiplierInY;
464 else if (this_centroid[1] > mMultiplierInY)
466 this_centroid[1] -= mMultiplierInY;
469 element_centroids.push_back(this_centroid);
472 return element_centroids;
475 void VoronoiVertexMeshGenerator::CreateVoronoiTessellation(std::vector<c_vector<double, 2> >& rSeedLocations)
478 std::vector<Node<2>*> nodes;
479 std::vector<VertexElement<2, 2>* > elements;
489 std::vector<boost_point> points;
492 for (
unsigned point_idx = 0 ; point_idx < rSeedLocations.size() ; point_idx++)
495 int point_x = int( floor( (rSeedLocations[point_idx][0] * mSamplingMultiplier) + 0.5) );
496 int point_y = int( floor( (rSeedLocations[point_idx][1] * mSamplingMultiplier) + 0.5) );
498 points.push_back( boost_point(point_x, point_y) );
502 std::vector<boost_point> offsets;
503 offsets.push_back( boost_point(-mMaxIntX, mMaxIntY) );
504 offsets.push_back( boost_point( 0, mMaxIntY) );
505 offsets.push_back( boost_point( mMaxIntX, mMaxIntY) );
506 offsets.push_back( boost_point( mMaxIntX, 0) );
507 offsets.push_back( boost_point( mMaxIntX, -mMaxIntY) );
508 offsets.push_back( boost_point( 0, -mMaxIntY) );
509 offsets.push_back( boost_point(-mMaxIntX, -mMaxIntY) );
510 offsets.push_back( boost_point(-mMaxIntX, 0) );
514 for (
unsigned rep = 0; rep < offsets.size(); rep++)
516 boost_point offset = offsets[rep];
517 for (
unsigned point_idx = 0; point_idx < rSeedLocations.size(); point_idx++)
519 boost_point new_point = boost_point(points[point_idx].x() + offset.x(), points[point_idx].y() + offset.y());
520 points.push_back(new_point);
540 voronoi_diagram<double> vd;
541 construct_voronoi(points.begin(), points.end(), &vd);
544 for (voronoi_diagram<double>::const_cell_iterator it = vd.cells().begin();
545 it != vd.cells().end();
549 const voronoi_diagram<double>::cell_type& cell = *it;
553 if (cell.source_index() < rSeedLocations.size())
556 std::vector<Node<2>*> nodes_this_elem;
559 const voronoi_diagram<double>::edge_type *edge = cell.incident_edge();
563 if (edge->is_primary())
566 double x_location = (edge->vertex0()->x()) / mSamplingMultiplier;
567 double y_location = (edge->vertex0()->y()) / mSamplingMultiplier;
570 Node<2>* p_this_node =
new Node<2>(nodes.size(),
false, x_location, y_location);
579 unsigned existing_node_idx = UINT_MAX;
581 for (
unsigned node_idx = 0; node_idx < nodes.size(); node_idx++)
584 const c_vector<double, 2>& r_existing_node_location = nodes[node_idx]->
rGetLocation();
587 if (fabs(r_existing_node_location[0] - p_this_node->
rGetLocation()[0]) < DBL_EPSILON)
589 if (fabs(r_existing_node_location[1] - p_this_node->
rGetLocation()[1]) < DBL_EPSILON)
592 existing_node_idx = node_idx;
597 if (existing_node_idx < UINT_MAX)
600 nodes_this_elem.push_back(nodes[existing_node_idx]);
606 nodes.push_back(p_this_node);
607 nodes_this_elem.push_back(p_this_node);
614 }
while (edge != cell.incident_edge());
622 for (voronoi_diagram<double>::const_cell_iterator it = vd.cells().begin();
623 it != vd.cells().end();
627 const voronoi_diagram<double>::cell_type& cell = *it;
631 if (cell.source_index() >= rSeedLocations.size())
634 const voronoi_diagram<double>::edge_type *edge = cell.incident_edge();
641 if (edge->is_infinite())
646 if (edge->is_primary())
648 c_vector<double, 2> vertex_location;
651 vertex_location[0] = (edge->vertex0()->x()) / mSamplingMultiplier;
652 vertex_location[1] = (edge->vertex0()->y()) / mSamplingMultiplier;
658 for (
unsigned node_idx = 0 ; node_idx < nodes.size() ; node_idx++)
661 const c_vector<double, 2>& r_existing_node_location = nodes[node_idx]->
rGetLocation();
664 if (fabs(r_existing_node_location[0] - vertex_location[0]) < DBL_EPSILON)
666 if (fabs(r_existing_node_location[1] - vertex_location[1]) < DBL_EPSILON)
669 nodes[node_idx]->SetAsBoundaryNode(
true);
677 }
while (edge != cell.incident_edge());
689 void VoronoiVertexMeshGenerator::ValidateInputAndSetMembers()
692 if ((mNumElementsX < 2) || (mNumElementsY < 2))
697 if (mElementTargetArea <= 0.0)
699 EXCEPTION(
"Specified target area must be strictly positive");
703 mTotalNumElements = mNumElementsX * mNumElementsY;
706 mMaxNumElems = std::max(mNumElementsX, mNumElementsY);
709 mMultiplierInX =
double(mNumElementsX) /
double(mMaxNumElems);
710 mMultiplierInY =
double(mNumElementsY) /
double(mMaxNumElems);
713 mSamplingMultiplier = 0.5 *
double(INT_MAX);
716 mMaxIntX = int( floor( (mMultiplierInX * mSamplingMultiplier) + 0.5 ) );
717 mMaxIntY = int( floor( (mMultiplierInY * mSamplingMultiplier) + 0.5 ) );
720 void VoronoiVertexMeshGenerator::ValidateSeedLocations(std::vector<c_vector<double, 2> >& rSeedLocations)
722 unsigned num_seeds = rSeedLocations.size();
729 double safe_distance = 1.5 / mSamplingMultiplier;
740 for (
unsigned seed_idx_one = 0; seed_idx_one < num_seeds; seed_idx_one++)
742 for (
unsigned seed_idx_two = seed_idx_one + 1; seed_idx_two < num_seeds; seed_idx_two++)
745 c_vector<double, 2> one_to_two = rSeedLocations[seed_idx_two] - rSeedLocations[seed_idx_one];
746 double distance = norm_2(one_to_two);
748 if (distance < safe_distance)
760 if (distance > DBL_EPSILON)
762 double multiplier = safe_distance / distance;
763 rSeedLocations[seed_idx_two] += (one_to_two * multiplier);
765 rSeedLocations[seed_idx_two][0] = fmod(rSeedLocations[seed_idx_two][0] + mMultiplierInX, mMultiplierInX);
766 rSeedLocations[seed_idx_two][1] = fmod(rSeedLocations[seed_idx_two][1] + mMultiplierInX, mMultiplierInX);
770 rSeedLocations[seed_idx_two][0] += safe_distance;
771 rSeedLocations[seed_idx_two][0] = fmod(rSeedLocations[seed_idx_two][0], mMultiplierInX);
785 std::vector<double> VoronoiVertexMeshGenerator::GetPolygonDistribution()
787 assert(mpMesh !=
nullptr);
790 unsigned num_elems = mpMesh->GetNumElements();
793 std::vector<unsigned> num_polygons(mMaxExpectedNumSidesPerPolygon - 2, 0);
796 std::vector<double> polygon_dist;
799 for (
unsigned elem_idx = 0; elem_idx < num_elems; elem_idx++)
801 unsigned num_nodes_this_elem = mpMesh->GetElement(elem_idx)->GetNumNodes();
804 assert(num_nodes_this_elem > 2);
805 assert(num_nodes_this_elem <= mMaxExpectedNumSidesPerPolygon);
808 num_polygons[num_nodes_this_elem - 3]++;
812 unsigned elems_accounted_for = 0;
813 for (
unsigned polygon = 0 ; polygon < num_polygons.size() ; polygon++)
815 elems_accounted_for += num_polygons[polygon];
817 polygon_dist.push_back(static_cast<double>(num_polygons[polygon]) / static_cast<double>(num_elems));
820 if (elems_accounted_for == num_elems)
829 double VoronoiVertexMeshGenerator::GetAreaCoefficientOfVariation()
831 assert(mpMesh !=
nullptr);
834 unsigned num_elems = mpMesh->GetNumElements();
835 assert(num_elems > 1);
840 for (
unsigned elem_idx = 0 ; elem_idx < num_elems ; elem_idx++)
842 double deviation = mpMesh->GetVolumeOfElement(elem_idx) - mElementTargetArea;
843 var += deviation * deviation;
846 var /=
static_cast<double>(num_elems - 1);
848 return sqrt(var) / mElementTargetArea;
851 void VoronoiVertexMeshGenerator::RefreshSeedsAndRegenerateMesh()
853 this->GenerateVoronoiMesh();
856 void VoronoiVertexMeshGenerator::SetMaxExpectedNumSidesPerPolygon(
unsigned maxExpectedNumSidesPerPolygon)
858 mMaxExpectedNumSidesPerPolygon = maxExpectedNumSidesPerPolygon;
861 unsigned VoronoiVertexMeshGenerator::GetMaxExpectedNumSidesPerPolygon()
863 return mMaxExpectedNumSidesPerPolygon;
866 #endif // BOOST_VERSION >= 105200
867 #if BOOST_VERSION < 105200
875 EXCEPTION(
"This is a dummy class. Build with Boost version 1.52 or above for functionality.");
878 #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