This voronoi implementation is absolutely awesome and just what I
needed!
Using Voronoi.regions() I'm able to get the convex polygon point sets
I need to make blocks crumble elegantly in a 2d physics simulation. I
had to do a bit of wrangling to get all the point groups into
counterclockwise order and remove duplicated duplicated points, but
the results are neat!
Check it out at:
http://jaketastic.com/game/NewProject.swf
instructions:
click "play"
click "load test area"
WASD = movement keys
SPACEBAR = shoot the dark green blocks and watch them shatter.
The example is still primitive and some Voronoi regions get missed due
to bugs in my point reordering code.
It may be that it's possible to do something with NodeName's
EdgeReorderer to get points in the right order, more efficiently than
my beastly counterclockwise sorter. I'd like to see something like
Voronoi.regionsCounterClockwise() unless there is some reason that the
point order is what it is.
And I'm not sure that duplicating the point data in the region results
helps anything. Since there is no rendering capability built in that
relies on it, I might presume that it's included to make drawing the
regions easier with the flash drawing api? It just feels kind of
unexpected to get the duplicated points in the point sets of regions
().
I'd also be very excited to see plotBounds() take polygon data so that
"we can make the fractal voronois-within-voronois", but that seems
like a tricky task.
Just for chuckles; here is my embarrassing counter clockwise point
reorderer:
(The Vector2D Class is used by the physics sim and has lots of handy
math methods, but it should be easy enough to substitute
Vector.<Point>. )
<pre>
/*
* Takes an array of Vector2D's (a polygon) and shifts them to place
the centroid (center) at the origin (0,0).
*/
public function centroidEquals(p:Array):Vector2D {
var centre:Vector2D = new Vector2D();
var pl:uint = p.length;
for (var i:uint = 0; i < pl; i++) {
centre.y -= p[i].y;
centre.x -= p[i].x;
}
centre.y /= pl;
centre.x /= pl;
for (var j:uint = 0; j < pl; j++) {
p[j].y += centre.y;
p[j].x += centre.x;
}
centre.multEquals(-1);
return centre;
}
private function counterClockwiseEquals(v2dArray:Array):Array {
var ccArray:Array = [];
var a1:Array = [];
var a2:Array = [];
var a3:Array = [];
var a4:Array = [];
for each (var pt:Vector2D in v2dArray) {
if (pt.x < 0 && pt.y < 0) {
a1.push(pt);
} else if (pt.x < 0 && pt.y > 0) {
a2.push(pt);
} else if (pt.x > 0 && pt.y > 0) {
a3.push(pt);
} else {
a4.push(pt);
}
}
if (a1[0]){
sortBySlope(a1, "highest");// Sort by y/x highest to lowest
for each (var p1:Vector2D in a1) {
ccArray.push(p1);
}
}
if (a2[0]){
sortBySlope(a2, "lowest");// Sort by y/x highest to lowest
for each (var p2:Vector2D in a2) {
ccArray.push(p2);
}
}
if (a3[0]){
sortBySlope(a3, "highest");// Sort by y/x lowest to highest
for each (var p3:Vector2D in a3) {
ccArray.push(p3);
}
}
if (a4[0]){
sortBySlope(a4, "lowest");// Sort by y/x highest to lowest
for each (var p4:Vector2D in a4) {
ccArray.push(p4);
}
}
return ccArray;
}
//TODO: make work better!
private function sortBySlope(v2dArray:Array, order:String):void {
var slope:Number;
var p:Array = [];
for each (var v:Vector2D in v2dArray) {
slope = new Number(Math.abs(v.y/v.x));
p.push(slope);
}
//trace("unsorted: "+v2dArray);
//Prepare Insertion sort.
var pl:uint = p.length;
var w:Number = p[0];
var u:Vector2D = v2dArray[0];
var d:Number;
var e:Vector2D;
var temp:Number;
var temt:Vector2D;
var j:uint;
for (var i:uint = 1; i < pl; i++) {
d = p[i];
e = v2dArray[i];
// Insertion sort.
temp = d;
temt = e;
if ( temp < w ) {
j = i;
while ( ( j > 0 ) && ( p[int(j - 1) ] > temp ) ) {
p[j] = p[int(j - 1)];
v2dArray[j] = v2dArray[int(j - 1)];
j--;
}
p[j] = d;
v2dArray[j] = e;
} else {
w = temp;
u = temt;
}
}
if (order == "highest") {
v2dArray.reverse();
}
//trace("Sorted: "+v2dArray);
}