malei-pku / incremental-voronoi-sets

Generator for incremental voronoi sets

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Incremental Voronoi Set generator

This project is an implementation of the incremental voronoi set generator described in the paper Incremental Voronoi sets for instant stippling by Lei Ma, Yanyun Chen, Yinling Qian and Hanqiu Sun.

./images/animation.gif

The paper describes an algorithm for real-time stippling and digital halftoning relying on so-called “Incremental Voronoi Sets” (IVS). An IVS is basically a set of ordered points generated by incrementally adding points to a Delaunay triangulation on a periodic (toroidal) domain. Each point added in sequence is added at the center of the largest current circumcircle of the triangles into the triangulation. This generates a blue noise pattern of points, and crucially the index of each point is inversely proportional to the area it’s Voronoi cell covers.

This repository contains an implementation of the generator for these sets. The generator outputs both a text file with all the points in order, as well as images for debug/visualization purposes. In order to generate the toroidal Delaunay triangulations, it uses the 2D Periodic Delaunay Triangulation generator from CGAL, and Cairo for the graphics.

Building and running

Dependencies

The dependencies for this project are CGAL, Cairo and GLM. CGAL itself uses Boost, and I noticed that on Arch Linux you needed to install that as well. I haven’t tested it super-thoroughly on different systems, but this should work for macOS (using Homebrew):

brew install cgal cairo boost glm

On Arch Linux, using pacman:

pacman -Sy cgal cairo boost glm

I’m pretty sure it’s the same on most UNIXy systems with package managers. Let me know if you have trouble.

Building

This project uses CMake for it’s build script, so build method is pretty standard. Doing a basic makefile build looks like this:

mkdir build
cd build
cmake ..
make

This will create a binary in the build folder called `ivs`.

Command line usage

Example usage would be

./ivs -n 4096 -c 10 -f ivs.png set.txt

This will create an IVS with 4096 points using 10 seed points, save the final image to ivs.png and save the set to a textfile `set.txt`. The text file contains the coordinates for the points (each coordinate is between 0 and 1) one per line.

Full usage:

Usage: ivs [options] [<output-file>]
	
The <output-file> option is a file to save the finished IVS set into. Each line
will have the X and Y coordinates of the dot (in the range [0,1)) separated by a
comma. If <output-file> is a "-", then print to stdout instead. 

Options:
    -h, --help                  Print this help text

    -n, --number                Number of total points to generate
        --seed <n>              Seed for RNG
    -c, --seed-count <n>        Number of initial seed points (default = 2)

    -f, --draw-final <file>     Save final image to file
    -i, --draw-inter <files>    Save intermediate images to file
                                Example: ivs_%07d.png

        --draw-voronoi          Draw the voronoi diagram
        --draw-delaunay         Draw the Delaunay triangulation
        --draw-circumcircles    Draw the circumcircles of the triangulation

    -p, --point-size <n>        Radius of a drawn point
    -l, --line-width <n>        Width a drawn line
    -o, --img-size <n>          Saved images size (output images are square, this
                                is the size of one side)

Sample images

25 points with Delaunay triangulation, Voronoi diagram and circumcircles drawn

./ivs -n 25 --draw-delaunay --draw-voronoi --draw-circumcircles -f n25-decorated.png

./images/n25-decorated.png

Set of 4096 points with 10 seed points

./ivs -n 4096 -c 10 -f c10n4096.png

./images/c10n4096.png

Performance

The implementation is quite performant. The paper suggest using a priority queue to store candidate circumcircles so that the algorithm will not be less than O(n²), which is eactly what I did, and it works very nicely. The details of the algorithm can be found in the file src/ivs.cpp (it’s has lengthy comments and documentation). The generator performs quite well: on my computer it generates an IVS set of 1024*1024 points in little under 3 minutes. The paper states it took them around 3800 seconds, so I’m pretty statisfied with that (most of the credit obviously belongs to CGAL and the papers authors for coming up with the idea in the first place).

Algorithm notes

Periodicity

I have made a number of Deluanay generators myself over the years, but I chose to go with the one from CGAL because it can generate periodic triangulations over a toroidal domain. The papers authors state that the purpose of this is to make the set tileable. While it is undoubtedly true that this is one benefit, I also suspect that the iterative algorithm generating it only really makes sense on a toroidal domain, because the boundary condition becomes really weird: if you generate a non-periodic Delaunay triangulation from some set of point in a restricted domain, by far the biggest circumcircles will be on triangles lying on the edges, and those circumcircles will be massive, and the circumcircle far away.

This is obviously because if you have a Delaunay triangulation where three points are almost collinear, the circumcircle of those three points will be huge (tending towards infinity). This will only happen on the edges, because in the middle of the triangulation, such a triangle would not be valid (as it would likely contain another point of the triangulation. As such, any new points added iteratively would almost always fall far outside of the domain we’re interested in. Using a periodic triangulation avoids all these pitfalls: all circumcircles are comparatively small.

Lattices

One issue I have noticed with this algorihtm is that some of the images it generates tend to have large scale structures in them in the form of hexagonal lattices. This is an image of 20000 points showing the effect, with lattices circled:

./images/lattices.png

In the Fourier transform of the image, you can see these sections as white “splotches” in the spectrum:

./images/c2n20000-spectrum.png

This is obviously undesirable for stippling purposes. These previous images were generated with two random seed points, and the issue can be lessened by increasing the number seed points. This is 20000 points with 100 seed points, as well as its spectrum:

./images/c100n20000.png

./images/c100n20000-spectrum.png

Upping the seed-points should be used with caution, though: the whole point of the algorithm is that the index of each point is inversely proportional with it’s covered area, and the seed points do not follow these rules. In addition, given that they have the lowest indexes, their “covered area” is by far the largest of any of the points, so they will almost always appear in the final stippling. It might be worth considering skipping these seed points entirely in the final rendering, but the details on that is fuzzy to me. You could also consider doing something like Lloyd relaxation on the initial seeds to be sure they’re a bit spread out, but I haven’t implemented or tried that.

In any case, you have to weigh the seed point count carefully: too few and you get these structures, too many and you miss the point of the technique.

License

Copyright 2020 Oskar Sigvardsson

This file is part of ivs-generator.

ivs-generator is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option) any
later version.

ivs-generator is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.

You should have received a copy of the GNU General Public License along with
ivs-generator. If not, see <https://www.gnu.org/licenses/>.

About

Generator for incremental voronoi sets

License:GNU General Public License v3.0


Languages

Language:C++ 87.0%Language:CMake 13.0%