refactor load/save functions

Use streams instead of filename.
Move load/write functions if modules where logical.
This commit is contained in:
Johann Dreo 2014-05-21 13:42:23 +02:00
commit c37cce25ed
5 changed files with 160 additions and 130 deletions

47
graph.py Normal file
View file

@ -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")

View file

@ -17,6 +17,7 @@ import shortpath
import lindenmayer import lindenmayer
import triangulation import triangulation
import voronoi import voronoi
import graph
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
@ -53,7 +54,8 @@ penrose_segments = set()
if args.penrose: if args.penrose:
LOGN( "Load the penrose tiling" ) 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: else:
LOGN( "Draw the penrose tiling" ) LOGN( "Draw the penrose tiling" )
@ -79,11 +81,11 @@ else:
penrose.draw( depth ) penrose.draw( depth )
# save this intermediate step # 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 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]: if args.tour != [None]:
for tour in args.tour: 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.notsp:
if args.tour == [None] or not args.pheromones: if args.tour == [None] or not args.pheromones:
@ -102,13 +105,14 @@ if args.notsp:
sys.exit(error_codes["NO-TSP"]) sys.exit(error_codes["NO-TSP"])
if args.pheromones: if args.pheromones:
phero = utils.load_matrix(args.pheromones) with open(args.pheromones) as fd:
phero = utils.load_matrix(fd)
else: else:
LOGN( "Solve the TSP with an Ant Colony Algorithm" ) LOGN( "Solve the TSP with an Ant Colony Algorithm" )
LOGN( "\tConvert the segment list into an adjacency list graph" ) 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" ) LOGN( "\tCompute a tour" )
max_it = 10 max_it = 10
@ -130,89 +134,68 @@ else:
trajs.append(traj) trajs.append(traj)
with open("d%i_tour.points" % depth, "w") as fd: with open("d%i_tour.points" % depth, "w") as fd:
for p in traj: utils.write_points( traj, fd )
fd.write("%f %f\n" % p)
with open("d%i_pheromones.mat" % depth, "w") as fd: with open("d%i_pheromones.mat" % depth, "w") as fd:
for row in phero: utils.write_matrix( phero, fd )
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" )
######################################################################## ########################################################################
# TRIANGULATION # TRIANGULATION
######################################################################## ########################################################################
triangulated = []
if args.triangulation: if args.triangulation:
triangulation_edges = utils.load_segments(args.triangulation) with open(args.triangulation) as fd:
triangulated = triangulation.load(args.triangulation)
else: else:
LOGN( "Compute the triangulation of the penrose vertices" ) LOGN( "Compute the triangulation of the penrose vertices" )
points = utils.vertices_of(penrose_segments) points = utils.vertices_of(penrose_segments)
triangles = triangulation.delaunay_bowyer_watson( points, do_plot = False ) 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" ) 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): def acute_triangle(triangle):
"""Return True if the center of the circumcircle of the given triangle lies inside the triangle. """Return True if the center of the circumcircle of the given triangle lies inside the triangle.
That is if the triangle is acute.""" That is if the triangle is acute."""
return triangulation.in_triangle( triangulation.circumcircle(triangle)[0], triangle ) 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 # Filter out triangles that are obtuse
# triangulated = list(filter_if_not( acute_triangle, tri_nohull ))
triangulated = list(filter_if_not( acute_triangle, triangles )) triangulated = list(filter_if_not( acute_triangle, triangles ))
LOGN( "\t\tRemoved", len(triangles)-len(triangulated), "triangles" ) LOGN( "\t\tRemoved", len(triangles)-len(triangulated), "triangles" )
triangulation_edges = triangulation.edges_of( triangulated ) with open("d%i_triangulation.triangles" % depth, "w") as fd:
with open("d%i_triangulation.segments" % depth, "w") as fd: triangulation.write( triangulated, fd )
for p0,p1 in triangulation_edges:
fd.write("%f %f %f %f\n" % (p0[0],p0[1],p1[0],p1[1]) ) triangulation_edges = triangulation.edges_of( triangulated )
######################################################################## ########################################################################
# VORONOÏ # VORONOÏ
######################################################################## ########################################################################
voronoi_graph = {}
if args.voronoi: if args.voronoi:
voronoi_graph = utils.load_adjacency(args.voronoi) with open(args.voronoi) as fd:
voronoi_graph = graph.load( fd )
else: else:
# LOGN( "Compute the nodes of the Voronoï diagram" ) # LOGN( "Compute the nodes of the Voronoï diagram" )
voronoi_tri_graph = voronoi.dual(triangulated) 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_tri_centers = voronoi_tri_graph.keys()
voronoi_graph = voronoi.merge_enclosed( voronoi_tri_graph, penrose_segments ) voronoi_graph = voronoi.merge_enclosed( voronoi_tri_graph, penrose_segments )
with open("d%i_voronoi.graph" % depth, "w") as fd: with open("d%i_voronoi.graph" % depth, "w") as fd:
for k in voronoi_graph: graph.write( voronoi_graph, fd )
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")
voronoi_edges = voronoi.edges_of( voronoi_graph ) voronoi_edges = graph.edges_of( voronoi_graph )
voronoi_centers = voronoi_graph.keys() voronoi_centers = graph.nodes_of( voronoi_graph )
######################################################################## ########################################################################

View file

@ -3,8 +3,8 @@ import sys
import math import math
from itertools import ifilterfalse as filter_if_not from itertools import ifilterfalse as filter_if_not
from utils import tour,LOG,LOGN,x,y from utils import tour,LOG,LOGN
from geometry import mid, middle from geometry import mid,middle,x,y
# Based on http://paulbourke.net/papers/triangulate/ # Based on http://paulbourke.net/papers/triangulate/
# Efficient Triangulation Algorithm Suitable for Terrain Modelling # Efficient Triangulation Algorithm Suitable for Terrain Modelling
@ -132,15 +132,6 @@ def bounds( vertices ):
return (xmin,ymin),(xmax,ymax) 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 ): def supertriangle( vertices, delta = 0.1 ):
"""Return a super-triangle that encloses all given points. """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: 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 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__": if __name__ == "__main__":
import random import random
import utils import utils

108
utils.py
View file

@ -17,80 +17,68 @@ def LOGN( *args ):
LOG("\n") LOG("\n")
def load_points( filename ): def load_points( stream ):
points = [] points = []
with open(filename) as fd: for line in stream:
for line in fd: if line.strip()[0] != "#":
if line.strip()[0] != "#": p = tuple([float(i) for i in line.split()])
p = tuple([float(i) for i in line.split()]) assert(len(p)==2)
assert(len(p)==2) points.append( p )
points.append( p )
return points 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 = [] segments = []
with open(filename) as fd: for line in stream:
for line in fd: if line.strip()[0] != "#":
if line.strip()[0] != "#": seg = line.strip()
edge = [float(i) for i in line.split()] assert(len(seg)==2)
assert(len(edge)==4) edge = []
segments.append( ((edge[0],edge[1]),(edge[2],edge[3])) ) for p in seg:
assert(len(p)==2)
point = tuple([float(i) for i in seg])
edge.append( point )
segments.append( edge )
return segments return segments
def load_triangles( filename ): def write_segments( segments, stream ):
triangles = [] for seg in segments:
with open(filename) as fd: for p in seg:
for line in fd: stream.write( "%f,%f " % ( x(p),y(p) ) )
if line.strip()[0] != "#": stream.write( "\n" )
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 load_matrix( filename ): def load_matrix( stream ):
matrix = {} matrix = {}
with open(filename) as fd: for line in stream:
for line in fd: if line.strip()[0] != "#":
if line.strip()[0] != "#": skey,svals = line.split(":")
skey,svals = line.split(":") key = tuple((float(i) for i in skey.split(',')))
key = tuple((float(i) for i in skey.split(','))) col = {}
col = {} for stri in svals.split():
for stri in svals.split(): sk,sv = stri.split("=")
sk,sv = stri.split("=") value = float(sv)
value = float(sv) k = tuple((float(i) for i in sk.split(",")))
k = tuple((float(i) for i in sk.split(","))) col[k] = value
col[k] = value matrix[key] = col
matrix[key] = col assert(len(matrix) == len(matrix[key]))
assert(len(matrix) == len(matrix[key]))
return matrix return matrix
def load_adjacency( filename ): def write_matrix( mat, stream):
graph = {} for row in mat:
with open(filename) as fd: key = "%f,%f:" % row
for line in fd: line = key
if line.strip()[0] != "#": for k in mat[row]:
skey,svals = line.split(":") val = mat[row][k]
key = tuple((float(i) for i in skey.split(','))) line += "%f,%f=%f " % (k[0],k[1],val)
graph[key] = [] stream.write( line + "\n" )
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 vertices_of( segments ): def vertices_of( segments ):

View file

@ -4,6 +4,7 @@
from utils import tour,LOG,LOGN,x,y from utils import tour,LOG,LOGN,x,y
import triangulation import triangulation
import geometry import geometry
import graph
def nodes( triangles ): def nodes( triangles ):
"""Compute the locations of the centers of all the circumscribed circles of the given 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 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 ): def merge_nodes( graph, n0, n1, n2 ):
"""Merge n0 and n1 nodes as n2 within the given graph.""" """Merge n0 and n1 nodes as n2 within the given graph."""
@ -179,7 +169,7 @@ if __name__ == "__main__":
delaunay_edges = triangulation.edges_of( triangles ) delaunay_edges = triangulation.edges_of( triangles )
voronoi_graph = dual( triangles ) voronoi_graph = dual( triangles )
voronoi_edges = edges_of( voronoi_graph ) voronoi_edges = graph.edges_of( voronoi_graph )
print voronoi_edges print voronoi_edges
ax = fig.add_subplot(111) ax = fig.add_subplot(111)