I guess that my problem is related to "convex hull", but no the same. All shapes in the drawing are rectangles with same width and height. Many are adjacent to each other. I want to combine those adjacent rectangles into polygons. Unlike "convex hull", the resuled polygons could be "hollow" inside.
Is there any open source algorithm available?
if your bounds are reasonable use a 2D array of edge counts, otherwise you'd have to use nested dictionaries.
because all widths and heights are the same you can uniquely identify an edge by a combination of x, y, and orientation(vertical or horizontal)
sample pseudocode: list_of_edges = new list arr_count = new int[][][]
of course, if you want to order the edges, then you'd have to pass through the array another time
sorry, this pseudocode is pretty sloppy, but you should get the general idea
If you're using a spatial processing library (like JTS [java], NTS [.net] or GEOS [c++], which are all open source and usable for commercial apps, unlike GPC) you can just Union the rectangles.
The general purpose way to do this is to build a graph of the edges of the inputs (rectangles), perform intersections, label the edges as on the inside or outside of the result, and just keep the outer edges. I don't know of a specific algorithm to treat rectangles, but it would likely be simiar, except, as noted, the math would be simpler.
I had to write an algorithm for merging adjacent polygons as part of an experiment project with HTML5 canvas (nothing glorious, a jigsaw puzzle :-) Holes in the resulting polygon are naturally supported. The Javascript routine is found in the function named Polygon.prototype.merge() in www dot raymondhill dot net / puzzle-rhill / jigsawpuzzle-rhill-3 dot js
The key is to remove segments which are duplicate, but of opposite direction. Rough explanation: A Point is {x:?,y:?}, a Segment is {ptA:?,ptB:?}, a Contour is {pts:[]} (a collection of connected Point objects), a Polygon is {contours:[]} (a collection of Contour objects.)
The merge algorithm collect all segments in a big fat pool of Segment objects, where duplicates are eliminated. First, all the segments of all the contours defining Polygon A are added to the pool. Then, all the segments of all contours defining Polygon B are added to the pool, but we test and remove for duplicate (easily done using a Point object as a hashkey).
Then we take a segment from the pool (randomly is fine), and we "walk" it until we reach a "dead end", that is, no more segment can be connected. This form one Contour object. We repeat until the whole collection of segments has been used. As segments are used, they are removed from the pool. "Walk" a segment means we take its end point, and we look up a segment which start point matches it.
As said, as a result we have a collection of Contour objects which define the Polygon. Some contours will be filled, some might be hollow. To determine whether a Contour is filled or hollow is just a matter of testing whether the Contour is clockwise or counterclockwise, or whether its area is positive or negative. It's a convention, in my case clockwise contours are filled, counterclockwise are hollow.
Here is my implementation, minus the specifics and minus error handling. Hopefully I copied/pasted enough for you to make it work right away, else refer to my JS file above for context:
When we "walk" the segment to create a contour, there is a case where a segment can connect to more than one segment:
Which can lead to two valid results (the algorithm above will lead randomly to one or the other):
Result 1, one filled contour:
Result 2, one filled contour, one hollow contour:
This shouldn't be a problem though, as your code should already be ready to handle holes.
Other important detail: The algorithm above doesn't get rid of intermediate points ('+'), in fact they are expected or else the algorithm won't work, as in the following case:
My understanding is that this is what you have. I imagine the algorithm could be extended to support such case by finding and adding the intersecting points beforehand (it was unnecessary in my case):
Hope this help.
P.S.: You can 'test' the algorithm with the jigsaw puzzle, by snapping pieces together to generate holes, etc.: http://www.raymondhill.net/puzzle-rhill/puzzle-rhill.php?puzzlePieces=16&puzzleComplexity=1&puzzleURL=http://www.public-domain-photos.com/free-stock-photos-4/travel/los-angeles/los-angeles-skyline.jpg&puzzleRotate=0&puzzleVersion=3
I would look into something like General Polygon Clipper. You're basically doing union (OR) polygon operations. The fact that they're all rectangles just makes the math a bit easier, but it could easily be done with something like GPC.
There are language wrappers for lots of languages there, too.
Simply test if the rectangles are touching and then run convex hull on the union of their points.
Or you could also manually test to see which side of the rectangles are touching and add the point in the correct order to a polygon object.
These assume closed polygons will suffice (can't have holes in it).
How about trying the following. I think this will work if designed properly.
Find the smallest emclosing rectangle, basically max-x, min-x and max-y and min-y. This will be our canvas for drawing. Initialise a 2D array of bits dx X dy where dx, dy are width of this outer rectangle, to all 0s.
Our objective is to find the contour, basically some corners of the rectangles so we can scale down this problem to a level where we can handle it computationally, once we have the points we can scale up to get the actual coordinates.
Scan through the above 2D array and mark a point 1 if it is contained in one of the given rectangle.
Now scan the 2D array and look for points whose neighbourhood has a 3:1 split, that means on 3 sides it has 1s and on one side 0s or vice versa. These points are those that will define the contour.
I think the complexity will be managiable if we can scale down the problem wisely.