improve graph building, save graph after building it and split of drawgraph
This commit is contained in:
parent
6df2b7e3b7
commit
a7ad682cbe
6 changed files with 116 additions and 28 deletions
|
@ -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])
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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))
|
||||
|
|
18
src/c3nav/routing/management/commands/drawgraph.py
Normal file
18
src/c3nav/routing/management/commands/drawgraph.py
Normal 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'])
|
Loading…
Add table
Add a link
Reference in a new issue