<?xml version="1.0" encoding="utf-8" ?>
<?xml-stylesheet type="text/xsl" href="/static/xsl/demos.xsl"?>
<demo title="Seamless Tiles ala Voronoi" xmlns:xhtml="http://www.w3.org/1999/xhtml">

<wiki>
= Seamless Tiles ala Voronoi =

The first time I saw a [http://en.wikipedia.org/wiki/Voronoi_diagram Voronoi Diagram] it was oddly compelling even though I had no idea what it represented or how it was created.
</wiki><xhtml:img src="/static/images/voronoi/simple_voronoi.png" style="float:left;margin-right:20px"/><wiki>
It actually took kinda a while to find out what it was called. &gt;.&lt;
</wiki><xhtml:img src="/static/images/voronoi/grid_voronoi.png" style="float:right;margin-left:20px"/><wiki>

The idea is actually pretty simple:
* select a number of points and associate a color with them
* for each point on a surface give it the color associated with the closest point

Naturally there is more to it than that, but this is not [http://en.wikipedia.org/wiki/Voronoi_diagram Wikipedia].
In this typical example (left), the points have been assigned a random color and a random position.

If the points are aligned in a grid, we end up with squares, and if we stagger step them like this:

</wiki><xhtml:img src="/static/images/voronoi/hex_voronoi.png" style="float:right;margin-left:20px"/><wiki>
</wiki>

<xhtml:pre style="width:6em;">. . . . .
 . . . .
. . . . .
 . . . .
. . . . .
</xhtml:pre>

<wiki>
it will produce hexagons.

= Wrap-around distance calculation =

So why are these Voronoi diagrams seamless? So they can be tiled, of course!

Just kidding... The reason they are tiled is because I used a wrap around space. I'm sorry, I know there is a nice math term for this sort of space, but I can't remember it and [http://www.google.com/search?q=math+coordinates+wrap+around googoo] is not helping me...

Usually when caclulating the distance between two points, it very simple:

/static/images/voronoi/distance_wrap.png

not much going on, good ole: a * a + b * b = c * c. [http://en.wikipedia.org/wiki/Pythagoras Pythagoras] was smart so I could be dumb.

Things are a little bit different in tile-land. Distance calculation has to take into consideration the idea that (0,0) and (w,h) are side-by-side. The edges wrap around:

/static/images/voronoi/distance_wrap2.png

In a non-tiled world, a value for x is just x, whereas in a tiled world it is both x and ( x modulo width ). In tilespace the distance between these points is 112, whereas in normal space it is 182. 

Put another way, a point (x,y) in tile space is also at ( x*i*w, y*i*h ), where i is some integer value. For example: w=10, h=10, (x,y) = (2,2) is also at (-8,8), (12,12), (22,22), etc.

Obviously this potentially changes which points are closest to each other and calculating distance in tile space we end up with images which will be seamless tiles.

This is true for all images(ie: procedural textures) created in this "modulo space". Expect future posts on this.

Luckly, this is not too tuff to computerate. Here is what the code looks like:
</wiki>

<code>int distanceSquared( float x, float y, int w, int h ) {
	float xdist = fabs( this-&gt;x - x );
	float ydist = fabs( this-&gt;y - y );

	// closer to wrap around?
	if ( xdist &gt; w / 2 ) {
		if ( this-&gt;x &lt; x ) {
			xdist = this-&gt;x + ( w - x );
		} else {
			xdist = x + ( w - this-&gt;x );
		}
	}
	// closer to wrap around?
	if ( ydist &gt; h / 2 ) {
		if ( this-&gt;y &lt; y ) {
			ydist = this-&gt;y + ( h - y );
		} else {
			ydist = y + ( h - this-&gt;y );
		}
	}
	return xdist * xdist + ydist * ydist;
}
</code>

<wiki>
= [http://code.google.com/p/brianin3d-misc/source/browse/trunk/random/cxx/Voronoi.cpp Voronoi.cpp] =

Of course this idea is so much fun I had to do an implementation, and I hope you will feel free to tear it to shreds or use it to make billions of dollars.
</wiki>

<code>
mkdir -p /tmp/voronoi
cd ${_}
wget http://brianin3d-misc.googlecode.com/svn/trunk/random/cxx/Voronoi.cpp
chmod 755 Voronoi.cpp 
./Voronoi.cpp 
eog voronoi.ppm 
</code>

<wiki>
It assumes "c++" in your path to compile itself. And it has tons of options for playing hide-the-voronoi:
</wiki>

<code>% Voronoi -h
Usage: Voronoi [options]
Generate fun Voronoi diagrams

	-w width     width of the image: default is 256
	-h width     height of the image: default is 256
	-f filename  filename to write to: default is voronoi.ppm
	-m MODE      0 is random, 1 is grid and 2 is hexagons: default is random(0)
	-n POINTS    number of points to use: default is 64
	             for non-random mode, it should be a perfect square
	             and width and height should be divisible by sqrt(n)
	             eg: if n is 64, width and height could be 256 cuz 0 = 256 % 8
	-a ANTI      enable, disable antialiasing: default is on(1)
	-k KOLOR     this enables a weird color mode, try -k 63: default is 0(off)
	-r RADIANS   rotate the points... kinda: default is 0

eg: Voronoi -m 2 -k 57 -r 0 &amp;&amp; xv -root -quit voronoi.ppm
eg: Voronoi &amp;&amp; xv -root -quit voronoi.ppm
</code>

<wiki>
here are some random samples:
/static/images/voronoi/voronoi_1.png /static/images/voronoi/voronoi_2.png /static/images/voronoi/voronoi_3.png /static/images/voronoi/voronoi_4.png /static/images/voronoi/voronoi_5.png /static/images/voronoi/voronoi_6.png

Note: you may sometimes notices some weirdness at the edges to to my slack anti-aliasing... sorry... it is pretty minimal.
</wiki>
<xhtml:pre style="display:none">
!!! What are you doing here? looking for some more madness?

Oh, you lucky dog! Here it is:

Voronoi -m 10 -k 0 -r 0.47857 -n 132 -w 128 -h 128  
Voronoi -m 10 -k 0 -r 1.75 -n 2 -w 128 -h 128  
Voronoi -m 10 -k 0 -r 1.75 -n 3 -w 128 -h 128  
Voronoi -m 10 -k 0 -r 1.75 -n 4 -w 128 -h 128  
Voronoi -m 10 -k 100 -r 0.15 -n 16 -w 128 -h 128  
Voronoi -m 10 -k 23 -r 0.15 -n 16 -w 128 -h 128  
Voronoi -m 10 -k 23 -r 0.7857 -n 12 -w 128 -h 128  
Voronoi -m 10 -k 23 -r 0.7857 -n 132 -w 128 -h 128  
Voronoi -m 10 -k 23 -r 0.7857 -n 32 -w 128 -h 128  
Voronoi -m 10 -k 23 -r 1.75 -n 32 -w 128 -h 128  
Voronoi -m 10 -k 25 -r 0.47857 -n 132 -w 128 -h 128  
Voronoi -m 10 -k 2 -r 0.47857 -n 132 -w 128 -h 128  
Voronoi -m 10 -k 2 -r 0.7857 -n 132 -w 128 -h 128  
Voronoi -m 10 -k 53 -r 1.75 -n 16 -w 128 -h 128  
Voronoi -m 10 -k 5 -r 0.47857 -n 132 -w 128 -h 128  
Voronoi -m 10 -k 5 -r 0.7857 -n 132 -w 128 -h 128  
Voronoi -m 10 -k 83 -r 0.15 -n 16 -w 128 -h 128  
Voronoi -m 10 -r 0.15 -n 16 -w 128 -h 128  
Voronoi -m 1 -k 0.1 -r -0.247857 -n 1256 -w 128 -h 128  
Voronoi -m 1 -k 0.1 -r -0.47857 -n 1256 -w 128 -h 128  
Voronoi -m 1 -k 0.1 -r 0.47857 -n 1256 -w 128 -h 128  
Voronoi -m 1 -k 0.5 -r -0.247857 -n 1256 -w 128 -h 128  
Voronoi -m 1 -k 0 -r 0.47857 -n 132 -w 128 -h 128  
Voronoi -m 1 -k 1 -r 0.47857 -n 1256 -w 128 -h 128  
Voronoi -m 1 -k 1 -r 0.47857 -n 132 -w 128 -h 128  
Voronoi -m 1 -k 1 -r 0.47857 -n 256 -w 128 -h 128  
Voronoi -m 1 -k 57 -r 0 -n 16 -w 128 -h 128  
Voronoi -m 1 -r 0.15 -n 16 -w 128 -h 128  
Voronoi -m 1 -r 0.2 -n 16 -w 128 -h 128  
Voronoi -m 1 -r 0.3 -n 16 -w 128 -h 128  
Voronoi -m 1 -r 0 -n 16 -w 128 -h 128  
Voronoi -m 2 -k 0.5 -r 1.75 -n 1256 -w 128 -h 128  
Voronoi -m 2 -k 0.5 -r 1.75 -n 4 -w 128 -h 128  
Voronoi -m 2 -k 0 -r 0.47857 -n 132 -w 128 -h 128  
Voronoi -m 2 -k 0 -r 1.75 -n 3 -w 128 -h 128  
Voronoi -m 2 -k 0 -r 1.75 -n 4 -w 128 -h 128  
Voronoi -m 2 -k 57 -r 0 -n 16 -w 128 -h 128 
Voronoi -m 2 -k 57 -r 0 -n 16 -w 128 -h 128  
Voronoi -m 2 -k 57 -r 1.3 -n 16 -w 128 -h 128  
</xhtml:pre>
</demo>

