Using Voronoi Diagrams to find area contributions and centerlines between a set of polygons
Problem description
Given a CAD file containing a set of elements belonging to different departments. Compute square footage of areas occupied by elements and their surrounding areas in each department.
The images below show a set of elements in different departments. Each department is assigned a color for visual clarity.
Introduction
After exploring different approaches to compute the square footage, we found that the simplest and most optimal one was to compute the individual areas (element+surrounding space) then sum up all areas in the same department. A new question arises, how to divide space occupied by an element(polygon) and all its neighbors?
Computing area contribution for each polygon
First thing to do is to find a bounding box around each element and get a set of polygons to work with. Next is to find the midpoints between every polygon and all its direct neighbors. What we’re referring to as centerline in this post is, in fact, the shape that spans all the midpoints between a polygon and its neighbors. We’re using a concept in computational geometry called Voronoi Diagrams to find the centerlines.
Voronoi Diagrams
The simplest definition of Voronoi Diagrams is it being the partition of a plane into a set of regions close to each of a set of objects. In other words, given a set of points in a plane, a Voronoi Region/Cell of a point A is an area encompassing points closer to A than any other points in the plane. To use Voronoi Diagrams with a set of polygons, we need to compute a cell for each segment of a given polygon. By performing a union on the resulting Voronoi cells, we find the centerlines between the polygon and its neighbors (See example below). Please note that these centerlines can also be used for other purposes such as indoor navigation or robot motion.
Voronoi Cell for each segment (with matching colors)
Voronoi Cells(in red) + Union of Voronoi Cells resulting in centerlines(purple)
Step-by-step process of finding the centerlines
- Build a bounding box (polygon) around each element.
- Extract segments from each polygon and assign them an id to associate them with their original polygon.
- Find the Voronoi Cell for each segment passed. We’re using Boost library to perform this operation.
- Union the Voronoi Cells for segments in each polygon.
The Boost library provides a very efficient and easy-to-use function to compute the Voronoi Diagrams of any set of non-intersecting segments (except endpoints of consecutive segments). By passing the segments of each polygon to Boost, we’re computing the Voronoi cell for each segment then we’re performing a boolean union of all resulting Voronoi cells. As mentioned before, the union will be a shape representing the centerlines between the polygon and all its direct neighbors.
Please note that in the following C++ example, our polygons are stored in a collection called vRanges. Also, segments are instances of the Segment_vd class which takes the coordinates of the segment endpoints and the index of the containing polygon as inputs to the constructor.
// building a collection of segments from each polygon
for (unsigned index_range=0; index_range<vRanges.size(); index_range++)
{
SpecialGondolaRange range = vRanges[index_range];
vRanges[index_range].bVoronoi_points_found = FALSE;
if (range.bIgnore)
continue;
for (int i=0; i< range.numPnts; i++)
{
int curr = i, next = i==range.numPnts-1?0:i+1;
DPoint3d currP=range.shapePnts[curr];
DPoint3d nextP=range.shapePnts[next];
currP.x = currP.x;
currP.y = currP.y;
currP.z = 0;
nextP.x = nextP.x;
nextP.y = nextP.y;
nextP.z = 0;
double dist = mdlVec_distanceXY(&currP, &nextP);
segments.push_back(Segment_vd(currP.x, currP.y, nextP.x, nextP.y, index_range));
}
}
printf("--");
std::vector<Segment_vd> segments_no_intersections;
// Construction of the Voronoi Diagram.
voronoi_diagram<double> vd;
construct_voronoi(points.begin(), points.end(),
segments.begin(), segments.end(),
&vd);
printf("--");
Conclusion
As shown above, Voronoi Diagrams were very essential in resolving our problem of area contribution by generating the midpoints between elements in our file. Please note that, for this tutorial we’ve used VS2005 and Boost library v1.74.0. The newer versions of Boost (+1.82) require at least C++11 and a more recent release of Visual Studio.
Helpful links:
https://www.boost.org/doc/libs/1_80_0/libs/polygon/doc/voronoi_diagram.htm
One Comment