Changed the API a bit. Fortune algorithm is run right away, with the list of edges available at Voronoi.edges. The edges are Edge objects. They can be trimmed to a rectangle using tools.img_coord. The general test cycle is now implemented inside unittests.run_test.
Changed the API a bit. Fortune algorithm is run right away, with the list of edges available at Voronoi.edges. The edges are Edge objects. They can be trimmed to a rectangle using tools.img_coord. The general test cycle is now implemented inside unittests.run_test.

--- a/test-random.py
+++ b/test-random.py
@@ -1,27 +1,16 @@
 #!/usr/bin/python
 
-from voronoi import *
-import cv2,cv
-import numpy
 import random
 import time
+
+import unittests
 
 # Config 
 width=1000
 height=1000
 npoints=1000
 #seed=1341469547
-#seed=1341529231
 seed=int(time.time())
-
-# Useful functions
-def toint(t2):
-    return (int(t2[0]),int(t2[1]))
-
-# Init open CV
-cv.NamedWindow('testwin')
-
-img = numpy.zeros((height,width, 1), numpy.uint8)
 
 # Voronoi
 points=[]
@@ -33,20 +22,5 @@
     p=(x,y)
     points.append(p)
 
-    
-for p in points:
-    #print 'point',p
-    cv2.circle(img,toint(p),2,255,-1)
-cv2.imshow("testwin",img)
+unittests.run_test(points,width,height)
 
-v=Voronoi(points,width,height)
-v.img=img
-edges=v.edges()
-for edge in edges:
-    cv2.line(img,toint(edge[0]),toint(edge[1]),255)
-
-
-# Show results
-cv2.imshow("testwin",img)
-cv2.waitKey(0)
-

--- a/test-verticaledge.py
+++ b/test-verticaledge.py
@@ -1,37 +1,17 @@
 #!/usr/bin/python
 
-from voronoi import *
-import cv2,cv
 import numpy
-import random
 import time
+
+import unittests
 
 # Config 
 width=500
 height=500
 
-# Init open CV
-cv.NamedWindow('testwin')
-
-img = numpy.zeros((height,width, 1), numpy.uint8)
-
 # Voronoi
 points=[(50,50),
         (100,50)]
-    
-for p in points:
-    print 'point',p
-    cv2.circle(img,(int(p[0]),int(p[1])),2,255,-1)
-cv2.imshow("testwin",img)
 
-v=Voronoi(points,width,height)
-v.img=img
-edges=v.edges()
-for edge in edges:
-    cv2.line(img,edge[0],edge[1],255)
+unittests.run_test(points,width,height)
 
-
-# Show results
-cv2.imshow("testwin",img)
-cv2.waitKey(0)
-

--- a/test-verticalmirror.py
+++ b/test-verticalmirror.py
@@ -1,26 +1,16 @@
 #!/usr/bin/python
 
-from voronoi import *
-import cv2,cv
-import numpy
 import random
 import time
+
+import unittests
 
 # Config 
 width=500
 height=500
-npoints=5
-seed=1
-#seed=int(time.time())
-
-# Useful functions
-def toint(t2):
-    return (int(t2[0]),int(t2[1]))
-
-# Init open CV
-cv.NamedWindow('testwin')
-
-img = numpy.zeros((height,width, 1), numpy.uint8)
+npoints=2
+#seed=1
+seed=int(time.time())
 
 # Voronoi
 points=[]
@@ -34,19 +24,5 @@
 #    points.append((x,height-y))
 #    points.append((width-x,height-y))
 
-for p in points:
-    #print 'point',p
-    cv2.circle(img,toint(p),2,255,-1)
-cv2.imshow("testwin",img)
+unittests.run_test(points,width,height)
 
-v=Voronoi(points,width,height)
-v.img=img
-edges=v.edges()
-for edge in edges:
-    cv2.line(img,toint(edge[0]),toint(edge[1]),255)
-
-
-# Show results
-cv2.imshow("testwin",img)
-cv2.waitKey(0)
-

file:b/tools.py (new)
--- /dev/null
+++ b/tools.py
@@ -1,1 +1,57 @@
+def img_coords(edge,width,height):
+    intersections=[]
 
+    # Intersection with north and south edges (horizontal)
+    if edge.direction[1]!=0:
+        # North (y=height)
+        t=(height-edge.r[1])/edge.direction[1]
+        x=edge.value_x(t)
+        if 0<x and x<width:
+            intersections.append(t)
+        # South (y=0)
+        t=-edge.r[1]/edge.direction[1]
+        x=edge.value_x(t)
+        if 0<x and x<width:
+            intersections.append(t)
+
+    # Intersections with east and west (vertical)
+    if edge.direction[0]!=0:
+        # East (x=height)
+        t=(width-edge.r[0])/edge.direction[0]
+        y=edge.value_y(t)
+        if 0<y and y<height:
+            intersections.append(t)
+        # West (x=0)
+        t=-edge.r[0]/edge.direction[0]
+        y=edge.value_y(t)
+        if 0<y and y<height:
+            intersections.append(t)
+
+    if len(intersections)==0:
+        return None # Line misses image completely
+
+    # Figure out the range of values the line takes inside the box
+    mint=min(intersections)
+    maxt=max(intersections)
+
+    # Determine what range of values the line defined as now takes
+    if edge.start==None: # Make sure to clip the edge if it is infinite
+        edge.start=mint # This is when the box is left
+
+    if edge.end==None: # Make sure to clip the edge if it is infinite
+        edge.end=maxt # This is when the box is left
+
+    p1t=edge.start
+    p2t=edge.end
+
+    if p2t<mint or p1t>maxt: # This edge lies outside of the box
+        return None
+
+    # Determine the points that the edge takes after being clipped by the box
+    p1t=max(p1t,mint)
+    p2t=min(p2t,maxt)
+
+    start=edge.value(p1t)
+    end=edge.value(p2t)
+    return ((int(start[0]),int(start[1])),(int(end[0]),int(end[1])))
+

file:b/unittests.py (new)
--- /dev/null
+++ b/unittests.py
@@ -1,1 +1,38 @@
+import numpy
+import voronoi
+import cv,cv2
+import tools
 
+# Useful functions
+def toint(t2):
+    return (int(t2[0]),int(t2[1]))
+
+# Run a test on a set of points. The test does the following:
+#  1) Creates a CV window named "testwin"
+#  2) Draw the points into it as tiny circles
+#  3) Draws the edges calculated by voronoi
+#  4) Waits for a keystroke
+# The testwin is created based on passed width and height
+def run_test(points,width,height):
+    # Init open CV
+    cv.NamedWindow('testwin')
+
+    img = numpy.zeros((height,width, 1), numpy.uint8)
+    
+    for p in points:
+        cv2.circle(img,toint(p),2,255,-1)
+
+    v=voronoi.Voronoi(points,width,height)
+    v.img=img
+    edges=v.edges
+    for edge in v.edges:
+        edge=tools.img_coords(edge,width,height)
+        if edge==None:
+            continue
+
+        cv2.line(img,edge[0],edge[1],255)
+
+    # Show results
+    cv2.imshow("testwin",img)
+    cv2.waitKey(0)
+

file:a/voronoi.py -> file:b/voronoi.py
--- a/voronoi.py
+++ b/voronoi.py
@@ -72,62 +72,6 @@
 
         return (t,s)
 
-    def img_coords(self,width,height):
-        intersections=[]
-
-        # Intersection with north and south edges (horizontal)
-        if self.direction[1]!=0:
-            # North (y=height)
-            t=(height-self.r[1])/self.direction[1]
-            x=self.value_x(t)
-            if 0<x and x<width:
-                intersections.append(t)
-            # South (y=0)
-            t=-self.r[1]/self.direction[1]
-            x=self.value_x(t)
-            if 0<x and x<width:
-                intersections.append(t)
-
-        # Intersections with east and west (vertical)
-        if self.direction[0]!=0:
-            # East (x=height)
-            t=(width-self.r[0])/self.direction[0]
-            y=self.value_y(t)
-            if 0<y and y<height:
-                intersections.append(t)
-            # West (x=0)
-            t=-self.r[0]/self.direction[0]
-            y=self.value_y(t)
-            if 0<y and y<height:
-                intersections.append(t)
-
-        if len(intersections)==0:
-            return None # Line misses image completely
-
-        # Figure out the range of values the line takes inside the box
-        mint=min(intersections)
-        maxt=max(intersections)
-
-        # Determine what range of values the line defined as now takes
-        if self.start==None: # Make sure to clip the edge if it is infinite
-            self.start=mint # This is when the box is left
-
-        if self.end==None: # Make sure to clip the edge if it is infinite
-            self.end=maxt # This is when the box is left
-
-        p1t=self.start
-        p2t=self.end
-
-        if p2t<mint or p1t>maxt: # This edge lies outside of the box
-            return None
-
-        # Determine the points that the edge takes after being clipped by the box
-        p1t=max(p1t,mint)
-        p2t=min(p2t,maxt)
-
-        start=self.value(p1t)
-        end=self.value(p2t)
-        return ((int(start[0]),int(start[1])),(int(end[0]),int(end[1])))
 
 class Node:
     def __init__(self):
@@ -314,7 +258,12 @@
                     break
             self.points.insert(insert,point)
 
-    def edges(self):
+        # Run
+        self.edges=[]
+        self.sites={}
+        self.run()
+
+    def run(self):
         self.root=None
         self.internal_edges=[]
 
@@ -339,7 +288,7 @@
             elif e.type==Event.TYPE_CIRCLE:
                 self.remove_parabola(e.parabola_node)
     
-        return self.finish_edges()
+        self.edges=self.finish_edges()
 
     def add_parabola(self,point):
 #        print 'add_parabola',point
@@ -486,9 +435,7 @@
                 else:
                     edge.start=-tmpedges[1].end
 
-            trim=edge.img_coords(self.width,self.height)
-            if trim!=None:
-                edges.append(trim)
+            edges.append(edge)
         return edges
  
     def remove_event(self,event):