refactor graph code

This commit is contained in:
Laura Klünder 2016-12-10 12:07:52 +01:00
parent e6978c6e61
commit 57ed2ec368
4 changed files with 65 additions and 51 deletions

View file

@ -10,7 +10,6 @@ from c3nav.routing.connection import GraphConnection
from c3nav.routing.level import GraphLevel from c3nav.routing.level import GraphLevel
from c3nav.routing.point import GraphPoint from c3nav.routing.point import GraphPoint
from c3nav.routing.room import GraphRoom from c3nav.routing.room import GraphRoom
from c3nav.routing.router import Router
class Graph: class Graph:
@ -21,23 +20,38 @@ class Graph:
for level in Level.objects.all(): for level in Level.objects.all():
self.levels[level.name] = GraphLevel(self, level) self.levels[level.name] = GraphLevel(self, level)
self.points = [] self.rooms = ()
self.points = ()
self.connections = [] self.connections = []
self.rooms = []
self.level_transfer_points = [] self.level_transfer_points = []
self.levelconnector_points = {} self.levelconnector_points = {}
# Building the Graph
def build(self): def build(self):
for level in self.levels.values(): for level in self.levels.values():
level.build() level.build()
# collect rooms and points
self.rooms = sum((level.rooms for level in self.levels.values()), []) self.rooms = sum((level.rooms for level in self.levels.values()), [])
self.points = sum((level.points for level in self.levels.values()), []) self.points = sum((level.points for level in self.levels.values()), [])
# create connections between levels
print() print()
self.connect_levelconnectors() self.connect_levelconnectors()
# convert everything to tuples
self.rooms = tuple(self.rooms)
self.points = tuple(self.points)
self.connections = tuple(self.connections)
# give numbers to rooms and points
for i, room in enumerate(self.rooms):
room.i = i
for i, point in enumerate(self.points):
point.i = i
print() print()
print('Total:') print('Total:')
print('%d points' % len(self.points)) print('%d points' % len(self.points))
@ -50,13 +64,41 @@ class Graph:
for name, level in self.levels.items(): for name, level in self.levels.items():
print(('Level %s:' % name), *(sorted((len(room.points) for room in level.rooms), reverse=True))) print(('Level %s:' % name), *(sorted((len(room.points) for room in level.rooms), reverse=True)))
def add_connection(self, from_point, to_point, distance=None):
self.connections.append(GraphConnection(self, from_point, to_point, distance))
def add_levelconnector_point(self, levelconnector, point):
self.levelconnector_points.setdefault(levelconnector.name, []).append(point)
def connect_levelconnectors(self):
for levelconnector in LevelConnector.objects.all():
center = levelconnector.geometry.centroid
points = self.levelconnector_points.get(levelconnector.name, [])
rooms = tuple(set(sum((point.rooms for point in points), [])))
if len(rooms) < 2:
print('levelconnector %s on levels %s at (%.2f, %.2f) has <2 rooms (%d%s)!' %
(levelconnector.name, ', '.join(level.name for level in levelconnector.levels.all()),
center.x, center.y, len(rooms), (' on level '+rooms[0].level.level.name) if rooms else ''))
continue
center_point = GraphPoint(center.x, center.y, rooms=rooms)
self.points.append(center_point)
levels = tuple(set(room.level for room in rooms))
for level in levels:
level.room_transfer_points.append(center_point)
level.points.append(center_point)
for room in rooms:
room.points.append(center_point)
for point in points:
center_point.connect_to(point)
point.connect_to(center_point)
# Loading/Saving the Graph
def serialize(self): 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.mpl_clear) for room in self.rooms) rooms = tuple((room.level.level.name, room.mpl_clear) for room in self.rooms)
points = tuple((point.x, point.y, tuple(room.i for room in point.rooms)) for point in self.points) points = tuple((point.x, point.y, tuple(room.i for room in point.rooms)) for point in self.points)
connections = tuple((conn.from_point.i, conn.to_point.i, conn.distance) for conn in self.connections) connections = tuple((conn.from_point.i, conn.to_point.i, conn.distance) for conn in self.connections)
@ -100,47 +142,12 @@ class Graph:
graph = cls.unserialize(pickle.load(f)) graph = cls.unserialize(pickle.load(f))
return graph return graph
def build_router(self): # Drawing
for room in self.rooms:
room.build_router()
self.transfer_points.extend(room.router.transfer_points)
self.router = Router()
self.router.build(self.transfer_points, global_routing=True)
def draw_pngs(self, points=True, lines=True): def draw_pngs(self, points=True, lines=True):
for level in self.levels.values(): for level in self.levels.values():
level.draw_png(points, lines) level.draw_png(points, lines)
def add_levelconnector_point(self, levelconnector, point): # Router
self.levelconnector_points.setdefault(levelconnector.name, []).append(point) def build_router(self):
for level in self.levels.values():
def connect_levelconnectors(self): level.build_router()
for levelconnector in LevelConnector.objects.all():
center = levelconnector.geometry.centroid
points = self.levelconnector_points.get(levelconnector.name, [])
rooms = tuple(set(sum((point.rooms for point in points), [])))
if len(rooms) < 2:
print('levelconnector %s on levels %s at (%.2f, %.2f) has <2 rooms (%d%s)!' %
(levelconnector.name, ', '.join(level.name for level in levelconnector.levels.all()),
center.x, center.y, len(rooms), (' on level '+rooms[0].level.level.name) if rooms else ''))
continue
center_point = GraphPoint(center.x, center.y, rooms=rooms)
self.points.append(center_point)
levels = tuple(set(room.level for room in rooms))
for level in levels:
level.room_transfer_points.append(center_point)
level.points.append(center_point)
for room in rooms:
room.points.append(center_point)
for point in points:
center_point.connect_to(point)
point.connect_to(center_point)
def add_connection(self, from_point, to_point, distance=None):
self.connections.append(GraphConnection(self, from_point, to_point, distance))

View file

@ -20,6 +20,7 @@ class GraphLevel():
self.room_transfer_points = [] self.room_transfer_points = []
self.rooms = [] self.rooms = []
# Building the Graph
def build(self): def build(self):
print() print()
print('Level %s:' % self.level.name) print('Level %s:' % self.level.name)
@ -99,6 +100,7 @@ class GraphLevel():
room.points.append(point) room.points.append(point)
self.graph.add_levelconnector_point(levelconnector, point) self.graph.add_levelconnector_point(levelconnector, point)
# Drawing
def draw_png(self, points=True, lines=True): def draw_png(self, points=True, lines=True):
filename = os.path.join(settings.RENDER_ROOT, 'level-%s.base.png' % self.level.name) 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) graph_filename = os.path.join(settings.RENDER_ROOT, 'level-%s.graph.png' % self.level.name)
@ -123,3 +125,8 @@ class GraphLevel():
draw.line(_line_coords(point, otherpoint, height), fill=(0, 255, 255)) draw.line(_line_coords(point, otherpoint, height), fill=(0, 255, 255))
im.save(graph_filename) im.save(graph_filename)
# Routing
def build_router(self):
for room in self.rooms:
room.build_router()

View file

@ -21,6 +21,7 @@ class GraphRoom():
self.points = [] self.points = []
# Building the Graph
def prepare_build(self): def prepare_build(self):
self.clear_geometry = self.geometry.buffer(-0.3, join_style=JOIN_STYLE.mitre) self.clear_geometry = self.geometry.buffer(-0.3, join_style=JOIN_STYLE.mitre)
@ -157,6 +158,7 @@ class GraphRoom():
point2.connect_to(point1) point2.connect_to(point1)
i += 1 i += 1
# Routing
def build_router(self): def build_router(self):
self.router = Router() self.router = Router()
self.router.build(self.points) self.router.build(self.points)

View file

@ -27,8 +27,6 @@ class Router():
for point, pk in self.points_pk.items(): for point, pk in self.points_pk.items():
for to_point, connection in point.connections.items(): for to_point, connection in point.connections.items():
if to_point not in self.points_pk: if to_point not in self.points_pk:
if not global_routing:
self.transfer_points.add(point)
continue continue
matrix[pk, self.points_pk[to_point]] = connection.distance matrix[pk, self.points_pk[to_point]] = connection.distance
if global_routing: if global_routing: