improve graph building, save graph after building it and split of drawgraph

This commit is contained in:
Laura Klünder 2016-12-05 12:09:43 +01:00
parent 6df2b7e3b7
commit a7ad682cbe
6 changed files with 116 additions and 28 deletions

View file

@ -1,6 +1,8 @@
class GraphConnection():
def __init__(self, graph, from_point, to_point):
self.graph = graph
self.from_point = from_point
self.to_point = to_point
if to_point in from_point.connections:
self.graph.connections.remove(from_point.connections[to_point])

View file

@ -1,25 +1,93 @@
import os
import pickle
from collections import OrderedDict
from itertools import permutations
from django.conf import settings
from c3nav.mapdata.models import Level
from c3nav.routing.graph.connection import GraphConnection
from c3nav.routing.graph.level import GraphLevel
from c3nav.routing.graph.point import GraphPoint
from c3nav.routing.graph.room import GraphRoom
class Graph():
default_filename = os.path.join(settings.DATA_DIR, 'graph.pickle')
def __init__(self):
self.levels = {}
self.levels = OrderedDict()
for level in Level.objects.all():
self.levels[level.name] = GraphLevel(self, level)
self.points = []
self.connections = []
self.rooms = []
self.levelconnector_points = {}
def build(self):
for level in self.levels.values():
level.build()
print('Total:')
self.points = sum((level.points for level in self.levels.values()), [])
print('%d points' % len(self.points))
self.rooms = sum((level.rooms for level in self.levels.values()), [])
print('%d rooms' % len(self.rooms))
self.connect_levelconnectors()
print('%d connections' % len(self.connections))
print()
def serialize(self):
for i, room in enumerate(self.rooms):
room.i = i
for i, point in enumerate(self.points):
point.i = i
rooms = tuple((room.level.level.name, room.geometry, room.mpl_paths) for room in self.rooms)
points = tuple((point.room.i, point.x, point.y) for point in self.points)
connections = tuple((conn.from_point.i, conn.to_point.i) for conn in self.connections)
return (rooms, points, connections)
def save(self, filename=None):
if filename is None:
filename = self.default_filename
with open(filename, 'wb') as f:
pickle.dump(self.serialize(), f)
@classmethod
def unserialize(cls, data):
graph = cls()
rooms, points, connections = data
graph.rooms = [GraphRoom(graph.levels[room[0]], room[1], room[2]) for room in rooms]
graph.points = [GraphPoint(graph.rooms[point[0]], point[1], point[2]) for point in points]
for point in graph.points:
point.room.points.append(point)
for room in graph.rooms:
room.level.rooms.append(room)
room.level.points.extend(room.points)
for from_point, to_point in connections:
graph.add_connection(graph.points[from_point], graph.points[to_point])
return graph
@classmethod
def load(cls, filename=None):
if filename is None:
filename = cls.default_filename
with open(filename, 'rb') as f:
graph = cls.unserialize(pickle.load(f))
return graph
def draw_pngs(self, points=True, lines=True):
for level in self.levels.values():
level.draw_png(points=points, lines=lines)

View file

@ -16,6 +16,7 @@ class GraphLevel():
def __init__(self, graph, level):
self.graph = graph
self.level = level
self.points = []
self.rooms = []
def build(self):
@ -31,6 +32,7 @@ class GraphLevel():
self.rooms.append(room)
def create_points(self):
print('Level %s:' % self.level.name)
for room in self.rooms:
room.create_points()
@ -48,7 +50,7 @@ class GraphLevel():
room.points.append(point)
if len(points) < 2:
print('door with <2 rooms (%d) detected!' % len(points))
print('door with <2 rooms (%d) detected at %s' % (len(points), center))
for from_point, to_point in permutations(points, 2):
from_point.connect_to(to_point)
@ -72,6 +74,10 @@ class GraphLevel():
for room in self.rooms:
room.connect_points()
self.points = sum((room.points for room in self.rooms), [])
print('%d points' % len(self.points))
print()
def draw_png(self, points=True, lines=True):
filename = os.path.join(settings.RENDER_ROOT, 'level-%s.base.png' % self.level.name)
graph_filename = os.path.join(settings.RENDER_ROOT, 'level-%s.graph.png' % self.level.name)
@ -79,19 +85,13 @@ class GraphLevel():
im = Image.open(filename)
height = im.size[1]
draw = ImageDraw.Draw(im)
i = 0
for room in self.rooms:
if lines:
for point in room.points:
for otherpoint, connection in point.connections.items():
draw.line(_line_coords(point, otherpoint, height), fill=(255, 100, 100))
if points:
for point in room.points:
i += 1
draw.ellipse(_ellipse_bbox(point.x, point.y, height), (200, 0, 0))
if lines:
for point in self.points:
for otherpoint, connection in point.connections.items():
draw.line(_line_coords(point, otherpoint, height), fill=(255, 100, 100))
if points:
print('level %s: %d points' % (self.level.name, i))
for point in self.points:
draw.ellipse(_ellipse_bbox(point.x, point.y, height), (200, 0, 0))
im.save(graph_filename)

View file

@ -11,7 +11,7 @@ from c3nav.routing.utils.mpl import polygon_to_mpl_paths
class GraphRoom():
def __init__(self, level, geometry):
def __init__(self, level, geometry, mpl_paths=None):
self.level = level
self.geometry = geometry
self.points = []
@ -19,7 +19,9 @@ class GraphRoom():
self.clear_geometry = geometry.buffer(-0.3, join_style=JOIN_STYLE.mitre)
self.empty = self.clear_geometry.is_empty
if not self.empty:
if mpl_paths is not None:
self.mpl_paths = mpl_paths
elif not self.empty:
self.mpl_paths = polygon_to_mpl_paths(self.clear_geometry.buffer(0.01, join_style=JOIN_STYLE.mitre))
def create_points(self):

View file

@ -1,3 +1,5 @@
import time
from django.core.management.base import BaseCommand
from c3nav.routing.graph import Graph
@ -6,18 +8,14 @@ from c3nav.routing.graph import Graph
class Command(BaseCommand):
help = 'build the routing graph'
def add_arguments(self, parser):
parser.add_argument('--draw-graph', action='store_const', const=True, default=False,
help='render a graph image')
parser.add_argument('--dont-draw-graph-points', action='store_const', const=True, default=False,
help='dont draw points on the graph image')
parser.add_argument('--dont-draw-graph-lines', action='store_const', const=True, default=False,
help='dont draw lines on the graph image')
def handle(self, *args, **options):
graph = Graph()
graph.build()
if options['draw_graph']:
graph.draw_pngs(points=not options['dont_draw_graph_points'], lines=not options['dont_draw_graph_lines'])
start = time.time()
graph.save()
print('Saved in %.4fs' % (time.time()-start))
start = time.time()
graph.load()
print('Loaded in %.4fs' % (time.time() - start))

View file

@ -0,0 +1,18 @@
from django.core.management.base import BaseCommand
from c3nav.routing.graph import Graph
class Command(BaseCommand):
help = 'graw the routing graph'
def add_arguments(self, parser):
parser.add_argument('--no-points', action='store_const', dest='points', const=False, default=True,
help='dont draw points on the graph image')
parser.add_argument('--no-lines', action='store_const', dest='lines', const=False, default=True,
help='dont draw lines on the graph image')
def handle(self, *args, **options):
graph = Graph.load()
graph.draw_pngs(points=options['points'], lines=options['lines'])