In this answer by @Jake to the question Filling specified area by random dots in TikZ I learned about the poisson disc sampling technique to generate nice looking random patterns.
Jake's answer provided a link to a page where the algorithm is described in detail, and some implementations (in Java, Python and Ruby) are provided.
Of course this immediately sparked my urge to do a lualatex implementation which will allow to generate this kind of patterns from tikz.
So I did it. So this is not a real question, since I have the answer (which I will post in short), but I needed to share it 🙂
But I don't want to miss the opportunity to ask about nice applications for this technique in tikz. In my answer I'll focus on pattern generation, but perhaps someone more imaginative than me can think of more awesome showcases (for example, tag cloud generation?)
Best Answer
As promised, here is my implementation. It is composed of two files:
poisson.lua
contains the implementation in Lua of the algorithm described here. The "main" function isgenerate_poisson()
which returns a Lua array of points, each point being a pair (x,y). In addition, the functionpoisson_points_list()
is provided, which transforms the data generated bygenerate_poisson()
into something that can be fed to TikZ'sforeach
loop.poisson.sty
is only a wrapper to call the Lua function with TeX syntax. It provides the macro\poissonpointslist
which receives four arguments: the width and height of the area to fill, the minimum distance allowed between points, and the "number of points" generated in some step of the algorithm, which is usually 20 or 30. Smaller values cause faster execution, but can leave some regions of the filled area with less dots.The intended way of using this is to evaluate the macro with a given set of parameters and store the result in another macro, e.g.:
And then this new macro can be used as part of a
\foreach
loop, like the following:Depending on the code in the loop, we can generate an interesting variety of designs (see "Examples" section).
The code
poisson.sty
poisson.lua
Examples
1. Dense distribution. Simply draw a dot at each coordinate:
2. Sparse distribution. Draw a solid disc with random radius at each point:
3. Sparse density, use a flower pic at each coordinate randomizing size and angle
4. More dense, use a bubble pic at each coordinate randomizing size
5. Same density as bubbles, use line segments with random angle and color
Update: Bonus
To celebrate the bounty, I'm extending the answer with some considerations about the order of the list returned by
\poissonpointslist
and some ideas to change it. I also made all non-globally required identifiers local, as suggested by Aditya in a comment (this forced also a change in the order in which the functions are declared in the lua file). I'm pasting the new code at the end.Order of the list
The list of coordinates returned by
\poissonpoinstslist
is in the order in which the algorithm generates the points. It start at a random point in the area, and then tries to find some neighbors which do not "collide" with other already set points. The growing pattern of the mesh of points is random, but always somewhat around a nucleus, as if it were the cristallization of a dissolution.The pattern can be made visible if we change the color at which each dot is drawn, while processing the list, as in the following example (which also prints the index inside each node):
The result is the following:
The first coordinate generated by the algorithm is the labelled as "1" which has the brighter fill. The second one is labelled as "2" and it is a bit darker, and so on. The growing pattern can be seen as a gradient of darkness.
In some scenarios it could be preferible that the order of the list were not dependent on the order in which the points were generated by the algorith, but instead having some other ordering. For example, if we want to draw the points from left-to-right and top-to-bottom, it would be preferable that the point labelled as "85" were indeed the first one, the "26" the second one, and so on.
In the code which is pasted at the end, I provide a new function
\poissonpointslistordered
which tries to do this (although the ordering is not perfect because there are not clear "rows" due to the random nature of the coordinates). Using this order, and the same code than above (only changing\poissonpointslist
to\poissonpointslistordered
), the result is now:This ordered list can be useful to create some effects like the following:
The new code
poisson.sty
poisson.lua