Just another Perl shrine | |
PerlMonks |
Re: Better maps with Math::Geometry::Voronoi, (Working* code)by BrowserUk (Patriarch) |
on Jul 03, 2008 at 07:50 UTC ( [id://695306]=note: print w/replies, xml ) | Need Help?? |
*almostThere are are still occasional "extra" points being included, but I believe these are being output (wrongly) from M::G::V, as with the duplicated points I noted here. And once that problem has been solved, the spurious edges that show up occasionally will go away. How it worksIf you look at the example (requires FireFox) that samtregar posted, and consider just the edges that form the overall outline of the shaded polygons. In the set of all the edges of all the small polygons, all the "internal edges", that is edges that are not part of the bounding polygon, will appear in two of the smaller polygons. But those edges making up the bounding polygon will only appear in one. By processing all the edges from all the small polygons through a filter selecting just those edges that only appear once in the total set of edges, you will be left with just those edges that make up the bounding polygon. So, the problem then becomes one of simply (!) re-constructing the boundary polygon from that disordered set of edges. The exclamation mark is because although the final cut of the reconstruction (reordering) process is actually quite simple, arriving at the algorithm was anything but. The problem on a simple scale, is that you end up with an array of arrays of arrays like this:
And you need to re-order them so that the (right-most) end of one edge mates up with the start (left-most) end of the next. And do this all the way down the list until the end of the last edge matches the start of the first. You can then take the set of starts (or ends) and the first (or last) point from the other end, and you end up with an ordered set of points to construct the closed polygon. The problem is that the end of the first point could match up with any of the subsequent edges. Start or end. Having tried half a dozen combinations of: sorting and then swapping; or swapping then sorting; or sorting, swapping some and then resorting (rinse, repeat); I finally arrived at the algorithm by working through the above dataset manually and noting what I did. I then reproduced that in code. The result is the following subroutine:
The POC code uses GD to plot the points (in red), the Voronoi diagram (in green), and the boundary polygon (in blue). (Update: Added the pre-filtered polygons in grey to show that incomplete polygons are being removed prior to the 1-edging process). There are three operational modes: -PAT=[square|diamond|random]. The square and diamond options show up the duplicate vertices problem noted elsewhere, (but I filter these out) and show that the algorthm works. The random (default) pattern takes another option (-N=nnn) which is the number of randomly generated points passed to M::G::V to start the thing off. This demonstrates that the algorithm is very fast, but also shows up the fact that my filtering process is not succeeding in filtering all the spurious elements. If you run with the default (-PAT=random -N=20), then most of the time everything is fine. If you increase that to -N=100, it will sometimes be fine, but will often show the effects of the spurious points. Run with -N=1000 and it will (mostly) draw the full bounding polygon, but usually with a few "extra" edges. Update Added a couple of extra test modes: -PAT=hex|hex2 which more clearly demonstrate the "spurious points" problem. (If you run this on linux, you'll need to tweak the line:system 'voronoi.png'; to cause the program to display the resulting .png) The code: ('scuse the mass of debug comments) <Reveal this spoiler or all in this thread>
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
In Section
Meditations
|
|