From c37cce25ed7deb7972d14a1552eee59120f4cacc Mon Sep 17 00:00:00 2001 From: Johann Dreo Date: Wed, 21 May 2014 13:42:23 +0200 Subject: [PATCH] refactor load/save functions Use streams instead of filename. Move load/write functions if modules where logical. --- graph.py | 47 +++++++++++++++++++++ run_all.py | 79 ++++++++++++++-------------------- triangulation.py | 44 ++++++++++++++----- utils.py | 108 +++++++++++++++++++++-------------------------- voronoi.py | 14 +----- 5 files changed, 161 insertions(+), 131 deletions(-) create mode 100644 graph.py diff --git a/graph.py b/graph.py new file mode 100644 index 0000000..c1165b9 --- /dev/null +++ b/graph.py @@ -0,0 +1,47 @@ + +from geometry import x,y + +def graph_of( segments ): + graph = {} + for start,end in segments: + graph[start] = graph.get( start, [] ) + graph[start].append( end ) + graph[end] = graph.get( end, [] ) + graph[end].append( start ) + return graph + + +def edges_of( graph ): + edges = set() + for k in graph: + for n in graph[k]: + if k != n and (k,n) not in edges and (n,k) not in edges: + edges.add( (k,n) ) + return list(edges) + + +def nodes_of( graph ): + return graph.keys() + + +def load( stream ): + graph = {} + for line in stream: + if line.strip()[0] != "#": + skey,svals = line.split(":") + key = tuple((float(i) for i in skey.split(','))) + graph[key] = [] + for sp in svals.split(): + p = tuple(float(i) for i in sp.split(",")) + assert(len(p)==2) + graph[key].append( p ) + return graph + + +def write( graph, stream ): + for k in graph: + stream.write( "%f,%f:" % (x(k),y(k)) ) + for p in graph[k]: + stream.write( "%f,%f " % (x(p),y(p)) ) + stream.write("\n") + diff --git a/run_all.py b/run_all.py index bf5bbfb..21d6ee0 100755 --- a/run_all.py +++ b/run_all.py @@ -17,6 +17,7 @@ import shortpath import lindenmayer import triangulation import voronoi +import graph parser = argparse.ArgumentParser() @@ -53,7 +54,8 @@ penrose_segments = set() if args.penrose: LOGN( "Load the penrose tiling" ) - penrose_segments = utils.load_segments(args.penrose) + with open(args.penrose) as fd: + penrose_segments = utils.load_segments(fd) else: LOGN( "Draw the penrose tiling" ) @@ -79,11 +81,11 @@ else: penrose.draw( depth ) # save this intermediate step - LOGN( "\tsegments",len(penrose.segments) ) - with open("d%i_penrose.segments" % depth, "w") as fd: - fd.write( str(penrose) ) - penrose_segments = penrose.segments + LOGN( "\tsegments",len(penrose_segments) ) + with open("d%i_penrose.segments" % depth, "w") as fd: + utils.write_segments( penrose_segments, fd ) + ######################################################################## @@ -94,7 +96,8 @@ trajs = [] if args.tour != [None]: for tour in args.tour: - trajs.append( utils.load_points(tour) ) + with open(tour) as fd: + trajs.append( utils.load_points(fd) ) if args.notsp: if args.tour == [None] or not args.pheromones: @@ -102,13 +105,14 @@ if args.notsp: sys.exit(error_codes["NO-TSP"]) if args.pheromones: - phero = utils.load_matrix(args.pheromones) + with open(args.pheromones) as fd: + phero = utils.load_matrix(fd) else: LOGN( "Solve the TSP with an Ant Colony Algorithm" ) LOGN( "\tConvert the segment list into an adjacency list graph" ) - G = utils.adjacency_from_set( penrose_segments ) + G = graph.graph_of( penrose_segments ) LOGN( "\tCompute a tour" ) max_it = 10 @@ -130,89 +134,68 @@ else: trajs.append(traj) with open("d%i_tour.points" % depth, "w") as fd: - for p in traj: - fd.write("%f %f\n" % p) + utils.write_points( traj, fd ) + with open("d%i_pheromones.mat" % depth, "w") as fd: - for row in phero: - key = "%f,%f:" % row - line = key - for k in phero[row]: - val = phero[row][k] - line += "%f,%f=%f " % (k[0],k[1],val) - fd.write( line + "\n" ) + utils.write_matrix( phero, fd ) ######################################################################## # TRIANGULATION ######################################################################## +triangulated = [] + if args.triangulation: - triangulation_edges = utils.load_segments(args.triangulation) + with open(args.triangulation) as fd: + triangulated = triangulation.load(args.triangulation) else: LOGN( "Compute the triangulation of the penrose vertices" ) points = utils.vertices_of(penrose_segments) triangles = triangulation.delaunay_bowyer_watson( points, do_plot = False ) - # LOGN( "\tCompute the convex hull of",len(points),"points" ) - # # Should convert the set into a list - # hull = hull.convex_hull( list(points) ) - # hull_edges = list(utils.tour(hull)) - # LOGN( "\t\tHull of",len(hull_edges),"edges" ) - LOGN( "\tRemove triangles that are not sub-parts of the Penrose tiling" ) - # def adjoin_hull(triangle): - # """Return True if the given triangle has at least one edge that is in the set hull_edges.""" - # for (p,q) in utils.tour(list(triangle)): - # if (p,q) in hull_edges or (q,p) in hull_edges: - # return True - # return False def acute_triangle(triangle): """Return True if the center of the circumcircle of the given triangle lies inside the triangle. That is if the triangle is acute.""" return triangulation.in_triangle( triangulation.circumcircle(triangle)[0], triangle ) - # FIXME at depth 3, some triangles have an edge in the convex hull... - # Filter out edges that are in hull_edges - # tri_nohull = list(filter_if_not( adjoin_hull, triangles )) # Filter out triangles that are obtuse - # triangulated = list(filter_if_not( acute_triangle, tri_nohull )) - triangulated = list(filter_if_not( acute_triangle, triangles )) LOGN( "\t\tRemoved", len(triangles)-len(triangulated), "triangles" ) - triangulation_edges = triangulation.edges_of( triangulated ) - with open("d%i_triangulation.segments" % depth, "w") as fd: - for p0,p1 in triangulation_edges: - fd.write("%f %f %f %f\n" % (p0[0],p0[1],p1[0],p1[1]) ) + with open("d%i_triangulation.triangles" % depth, "w") as fd: + triangulation.write( triangulated, fd ) + +triangulation_edges = triangulation.edges_of( triangulated ) ######################################################################## # VORONOÏ ######################################################################## +voronoi_graph = {} + if args.voronoi: - voronoi_graph = utils.load_adjacency(args.voronoi) + with open(args.voronoi) as fd: + voronoi_graph = graph.load( fd ) else: # LOGN( "Compute the nodes of the Voronoï diagram" ) voronoi_tri_graph = voronoi.dual(triangulated) - voronoi_tri_edges = voronoi.edges_of( voronoi.dual(triangulated) ) + voronoi_tri_edges = graph.edges_of( voronoi.dual(triangulated) ) voronoi_tri_centers = voronoi_tri_graph.keys() voronoi_graph = voronoi.merge_enclosed( voronoi_tri_graph, penrose_segments ) with open("d%i_voronoi.graph" % depth, "w") as fd: - for k in voronoi_graph: - fd.write( "%f,%f:" % (x(k),y(k)) ) - for p in voronoi_graph[k]: - fd.write( "%f,%f " % (x(p),y(p)) ) - fd.write("\n") + graph.write( voronoi_graph, fd ) -voronoi_edges = voronoi.edges_of( voronoi_graph ) -voronoi_centers = voronoi_graph.keys() +voronoi_edges = graph.edges_of( voronoi_graph ) +voronoi_centers = graph.nodes_of( voronoi_graph ) ######################################################################## diff --git a/triangulation.py b/triangulation.py index 913f749..d763f19 100644 --- a/triangulation.py +++ b/triangulation.py @@ -3,8 +3,8 @@ import sys import math from itertools import ifilterfalse as filter_if_not -from utils import tour,LOG,LOGN,x,y -from geometry import mid, middle +from utils import tour,LOG,LOGN +from geometry import mid,middle,x,y # Based on http://paulbourke.net/papers/triangulate/ # Efficient Triangulation Algorithm Suitable for Terrain Modelling @@ -132,15 +132,6 @@ def bounds( vertices ): return (xmin,ymin),(xmax,ymax) -def edges_of( triangulation ): - """Return a list containing the edges of the given list of 3-tuples of points""" - edges = [] - for t in triangulation: - for e in tour(list(t)): - edges.append( e ) - return edges - - def supertriangle( vertices, delta = 0.1 ): """Return a super-triangle that encloses all given points. The super-triangle has its base at the bottom and encloses the bounding box at a distance given by: @@ -345,6 +336,37 @@ def delaunay_bowyer_watson( points, supertri = None, superdelta = 0.1, epsilon = return triangulation +def edges_of( triangulation ): + """Return a list containing the edges of the given list of 3-tuples of points""" + edges = [] + for t in triangulation: + for e in tour(list(t)): + edges.append( e ) + return edges + + +def load( stream ): + triangles = [] + for line in stream: + if line.strip()[0] != "#": + tri = line.split() + assert(len(tri)==3) + triangle = [] + for p in tri: + assert(len(p)==2) + point = [ (float(y),float(y)) for i,j in p.split(",")] + triangle.append( point ) + triangles.append( triangle ) + return triangles + + +def write( triangles, stream ): + for tri in triangles: + assert(len(tri)==3) + p,q,r = tri + stream.write("%f,%f %f,%f %f,%f\n" % ( x(p),y(p), x(q),y(q), x(r),y(r) ) ) + + if __name__ == "__main__": import random import utils diff --git a/utils.py b/utils.py index 7ee630b..758f490 100644 --- a/utils.py +++ b/utils.py @@ -17,80 +17,68 @@ def LOGN( *args ): LOG("\n") -def load_points( filename ): +def load_points( stream ): points = [] - with open(filename) as fd: - for line in fd: - if line.strip()[0] != "#": - p = tuple([float(i) for i in line.split()]) - assert(len(p)==2) - points.append( p ) + for line in stream: + if line.strip()[0] != "#": + p = tuple([float(i) for i in line.split()]) + assert(len(p)==2) + points.append( p ) return points -def load_segments( filename ): +def write_points( points, stream ): + for p in points: + stream.write( "%f,%f\n" % ( x(p),y(p) ) ) + + +def load_segments( stream ): segments = [] - with open(filename) as fd: - for line in fd: - if line.strip()[0] != "#": - edge = [float(i) for i in line.split()] - assert(len(edge)==4) - segments.append( ((edge[0],edge[1]),(edge[2],edge[3])) ) + for line in stream: + if line.strip()[0] != "#": + seg = line.strip() + assert(len(seg)==2) + edge = [] + for p in seg: + assert(len(p)==2) + point = tuple([float(i) for i in seg]) + edge.append( point ) + segments.append( edge ) return segments -def load_triangles( filename ): - triangles = [] - with open(filename) as fd: - for line in fd: - if line.strip()[0] != "#": - tri = [float(i) for i in line.split()] - assert(len(tri)==6) - triangles.append( ((tri[0],tri[1]),(tri[2],tri[3]),(tri[4],tri[5])) ) - return triangles +def write_segments( segments, stream ): + for seg in segments: + for p in seg: + stream.write( "%f,%f " % ( x(p),y(p) ) ) + stream.write( "\n" ) -def load_matrix( filename ): +def load_matrix( stream ): matrix = {} - with open(filename) as fd: - for line in fd: - if line.strip()[0] != "#": - skey,svals = line.split(":") - key = tuple((float(i) for i in skey.split(','))) - col = {} - for stri in svals.split(): - sk,sv = stri.split("=") - value = float(sv) - k = tuple((float(i) for i in sk.split(","))) - col[k] = value - matrix[key] = col - assert(len(matrix) == len(matrix[key])) + for line in stream: + if line.strip()[0] != "#": + skey,svals = line.split(":") + key = tuple((float(i) for i in skey.split(','))) + col = {} + for stri in svals.split(): + sk,sv = stri.split("=") + value = float(sv) + k = tuple((float(i) for i in sk.split(","))) + col[k] = value + matrix[key] = col + assert(len(matrix) == len(matrix[key])) return matrix -def load_adjacency( filename ): - graph = {} - with open(filename) as fd: - for line in fd: - if line.strip()[0] != "#": - skey,svals = line.split(":") - key = tuple((float(i) for i in skey.split(','))) - graph[key] = [] - for sp in svals.split(): - p = tuple(float(i) for i in sp.split(",")) - assert(len(p)==2) - graph[key].append( p ) - return graph - - -def adjacency_from_set( segments ): - graph = {} - for start,end in segments: - graph[start] = graph.get( start, [] ) - graph[start].append( end ) - graph[end] = graph.get( end, [] ) - graph[end].append( start ) - return graph +def write_matrix( mat, stream): + for row in mat: + key = "%f,%f:" % row + line = key + for k in mat[row]: + val = mat[row][k] + line += "%f,%f=%f " % (k[0],k[1],val) + stream.write( line + "\n" ) def vertices_of( segments ): diff --git a/voronoi.py b/voronoi.py index 0fdc19a..1876e91 100644 --- a/voronoi.py +++ b/voronoi.py @@ -4,6 +4,7 @@ from utils import tour,LOG,LOGN,x,y import triangulation import geometry +import graph def nodes( triangles ): """Compute the locations of the centers of all the circumscribed circles of the given triangles""" @@ -68,17 +69,6 @@ def dual( triangles ): return graph -def edges_of( graph ): - # edges = set() - edges = [] - for k in graph: - for n in graph[k]: - if k != n and (k,n) not in edges and (n,k) not in edges: - # edges.add( (k,n) ) - edges.append( (k,n) ) - return edges - - def merge_nodes( graph, n0, n1, n2 ): """Merge n0 and n1 nodes as n2 within the given graph.""" @@ -179,7 +169,7 @@ if __name__ == "__main__": delaunay_edges = triangulation.edges_of( triangles ) voronoi_graph = dual( triangles ) - voronoi_edges = edges_of( voronoi_graph ) + voronoi_edges = graph.edges_of( voronoi_graph ) print voronoi_edges ax = fig.add_subplot(111)