Voronoi diagram

From Rosetta Code
Revision as of 10:45, 19 July 2011 by rosettacode>Markhobley (minor grammatical fix)
Voronoi diagram is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

A Voronoi diagram is a diagram consisting of a number of sites. Each Voronoi s also has a Voronoi cell consisting of all points closest to s.

The task is to demonstrate how to generate and display a Voroni diagram.

C

C code drawing a color map of a set of Voronoi sites. Image is in PNM P6, written to stdout. Run as a.out > stuff.pnm. <lang c>#include <stdio.h>

  1. include <stdlib.h>
  2. include <string.h>
  1. define N_SITES 150

double site[N_SITES][2]; unsigned char rgb[N_SITES][3];

int size_x = 640, size_y = 480;

inline double sq2(double x, double y) { return x * x + y * y; }

void gen_map() { int i, j, k, nearest = 0; unsigned char *ptr, *buf, color; double dist, d;

ptr = buf = malloc(3 * size_x * size_y); for (i = 0; i < size_y; i++) { for (j = 0; j < size_x; j++, ptr += 3) { dist = 1e100; for (k = 0; k < N_SITES; k++) { d = sq2(i - site[k][1], j - site[k][0]); if (d >= dist) continue; dist = d; nearest = k; } memcpy(ptr, rgb[nearest], 3); } }

/* draw sites */ for (k = 0; k < N_SITES; k++) { color = (rgb[k][0]*.25 + rgb[k][1]*.6 + rgb[k][2]*.15 > 80) ? 0 : 255;

for (i = site[k][1] - 1; i <= site[k][1] + 1; i++) { if (i < 0 || i >= size_y) continue; for (j = site[k][0] - 1; j <= site[k][0] + 1; j++) { if (j < 0 || j >= size_x) continue; ptr = buf + 3 * (i * size_x + j); ptr[0] = ptr[1] = ptr[2] = color; } } }

printf("P6\n%d %d\n255\n", size_x, size_y); fflush(stdout); fwrite(buf, size_y * size_x * 3, 1, stdout); }

int main() { int i; for (i = 0; i < N_SITES; i++) { site[i][0] = (double)rand() / RAND_MAX * size_x; site[i][1] = (double)rand() / RAND_MAX * size_y; rgb[i][0] = (double)rand() / RAND_MAX * 256; rgb[i][1] = (double)rand() / RAND_MAX * 256; rgb[i][2] = (double)rand() / RAND_MAX * 256; } gen_map(); return 0; }</lang>

PureBasic

Voronoi Diagram in PureBasic

<lang PureBasic>Structure VCoo

 x.i:  y.i
 Colour.i: FillColour.i

EndStructure

Macro RandInt(MAXLIMIT)

 Int(MAXLIMIT*(Random(#MAXLONG)/#MAXLONG))

EndMacro

Macro SQ2(X, Y)

 ((X)*(X) + (Y)*(Y))

EndMacro

Procedure GenRandomPoints(Array a.VCoo(1), xMax, yMax, cnt)

 Protected i, j, k, l
 cnt-1
 Dim a(cnt)
 For i=0 To cnt
   a(i)\x = RandInt(xMax): a(i)\y = RandInt(yMax)
   j = RandInt(255): k = RandInt(255): l = RandInt(255)
   a(i)\Colour = RGB(j, k, l)
   a(i)\FillColour = RGB(255-j, 255-k, 255-l)
 Next i
 ProcedureReturn #True

EndProcedure

Procedure MakeVoronoiDiagram(Array a.VCoo(1),xMax, yMax)

 Protected i, x, y, img, dist.d, dt.d
 img = CreateImage(#PB_Any, xMax+1, yMax+1)
 If StartDrawing(ImageOutput(img))
   For x=0 To xMax
     For y=0 To yMax
       dist = Infinity()
       For i=0 To ArraySize(a())
         dt = SQ2(x-a(i)\x, y-a(i)\y)
         If dt >= dist :Continue: EndIf
         dist = dt
         If x=a(i)\x And y=a(i)\y
           Plot(x,y,a(i)\Colour)
         Else
           Plot(x,y,a(i)\FillColour)
         EndIf
       Next
     Next
   Next
   StopDrawing()
 EndIf
 ProcedureReturn img 

EndProcedure

Main code

Define img, x, y, file$ Dim V.VCoo(0) x = 640: y = 480 If Not GenRandomPoints(V(), x, y, 150): End: EndIf img = MakeVoronoiDiagram(V(), x, y) If img And OpenWindow(0, 0, 0, x, y, "Voronoi Diagram in PureBasic", #PB_Window_SystemMenu)

 ImageGadget(0, 0, 0, x, y, ImageID(img))
 Repeat: Until WaitWindowEvent() = #PB_Event_CloseWindow

EndIf

UsePNGImageEncoder() file$ = SaveFileRequester("Save Image?", "Voronoi_Diagram_in_PureBasic.png", "PNG|*.png", 0) If file$ <> ""

 SaveImage(img, file$, #PB_ImagePlugin_PNG)

EndIf</lang>

Python

This implementation takes in a list of points, each point being a tuple and returns a dictionary consisting of all the points at a given site. <lang python>def generate_voronoi(points): minx, miny = points[0] maxx, maxy = points[0] for x, y in points: ## Find the minimum x and minimum y if x < minx: minx = x if x > maxx: maxx = x if y < miny: miny = y if y > maxy: maxy = y nx = [] ny = [] voronoi = {} hypot = math.hypot cell_num = 0 for x, y in points: voronoi[cell_num] = [] nx.append(x) ny.append(y) cell_num += 1 for y in range(miny-height_padding, maxy): for x in range(minx-width_padding, maxx): dmin = hypot(maxx+-1, maxy-1) j = -1 for i in range(cell_num): d = hypot(nx[i]-x, ny[i]-y) if d < dmin: dmin = d j = i voronoi[j].append((x, y)) return voronoi </lang>

Sample Output:

<lang python>voronoi = generate_voronoi([(0, 0), (5, 5)]) voronoi[0] : (0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (5, 0), (0, 1), (1, 1), (2, 1), (3, 1), (4, 1), (0, 2), (1, 2), (2, 2), (3, 2), (0, 3), (1, 3), (2, 3), (0, 4), (1, 4), (0, 5) // Points closest to (0, 0) voronoi[1] : (5, 1), (4, 2), (5, 2), (3, 3), (4, 3), (5, 3), (2, 4), (3, 4), (4, 4), (5, 4), (1, 5), (2, 5), (3, 5), (4, 5), (5, 5) // Points closest to (5, 5) </lang>