buildgraph: points with multiple rooms instead of points with no rooms

This commit is contained in:
Laura Klünder 2016-12-09 20:01:08 +01:00
parent 6b836e5258
commit 23139ecdf8
5 changed files with 103 additions and 73 deletions

View file

@ -13,7 +13,7 @@ from c3nav.routing.room import GraphRoom
from c3nav.routing.router import Router
class Graph():
class Graph:
default_filename = os.path.join(settings.DATA_DIR, 'graph.pickle')
def __init__(self):
@ -24,27 +24,31 @@ class Graph():
self.points = []
self.connections = []
self.rooms = []
self.no_level_points = []
self.levelconnector_points = {}
self.transfer_points = []
self.router = Router()
self.level_transfer_points = []
self.levelconnector_points = {}
def build(self):
for level in self.levels.values():
level.build()
self.rooms = sum((level.rooms for level in self.levels.values()), [])
self.points = sum((level.points for level in self.levels.values()), [])
print()
self.connect_levelconnectors()
print()
print('Total:')
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 level transfer points' % len(self.no_level_points))
print('%d level transfer points' % len(self.level_transfer_points))
print('%d connections' % len(self.connections))
print()
print('Points per room:')
for name, level in self.levels.items():
print(('Level %s:' % name), *(sorted((len(room.points) for room in level.rooms), reverse=True)))
def serialize(self):
for i, room in enumerate(self.rooms):
@ -53,17 +57,11 @@ class Graph():
for i, point in enumerate(self.points):
point.i = i
def i_or_none(obj):
return None if obj is None else obj.i
def name_or_none(obj):
return None if obj is None else obj.level.name
rooms = tuple((room.level.level.name, room.geometry, room.mpl_clear) for room in self.rooms)
points = tuple((point.x, point.y, i_or_none(point.room), name_or_none(point.level)) for point in self.points)
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)
connections = tuple((conn.from_point.i, conn.to_point.i, conn.distance) for conn in self.connections)
return (rooms, points, connections)
return rooms, points, connections
def save(self, filename=None):
if filename is None:
@ -76,12 +74,18 @@ class Graph():
graph = cls()
rooms, points, connections = data
def by_key_or_none(collection, key):
return None if key is None else collection[key]
graph.rooms = [GraphRoom(graph.levels[room[0]], mpl_clear=room[1]) for room in rooms]
graph.points = [GraphPoint(point[0], point[1], rooms=tuple(graph.rooms[i] for i in point[2]))
for point in points]
graph.rooms = [GraphRoom(graph.levels[room[0]], room[1], room[2]) for room in rooms]
graph.points = [GraphPoint(point[0], point[1], by_key_or_none(graph.rooms, point[2]),
by_key_or_none(graph.levels, point[3]), graph) for point in points]
for point in graph.points:
for room in point.rooms:
room.points.append(point)
for name, level in graph.levels.items():
level.rooms = [room for room in graph.rooms if room.level == level]
level.points = list(set(sum((room.points for room in level.rooms), [])))
level.room_transfer_points = [point for point in level.points if len(point.rooms) > 1]
for from_point, to_point, distance in connections:
graph.add_connection(graph.points[from_point], graph.points[to_point], distance)
@ -101,6 +105,7 @@ class Graph():
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):
@ -113,8 +118,27 @@ class Graph():
def connect_levelconnectors(self):
for levelconnector in LevelConnector.objects.all():
center = levelconnector.geometry.centroid
center_point = GraphPoint(center.x, center.y, graph=self)
for point in self.levelconnector_points.get(levelconnector.name, []):
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)

View file

@ -15,34 +15,39 @@ class GraphLevel():
def __init__(self, graph, level):
self.graph = graph
self.level = level
self.points = []
self.no_room_points = []
self.room_transfer_points = []
self.rooms = []
def build(self):
print()
print('Level %s:' % self.level.name)
self.collect_rooms()
print('%d rooms' % len(self.rooms))
for room in self.rooms:
room.prepare_build()
room.build_points()
self.create_doors()
self.create_levelconnectors()
self.points = sum((room.points for room in self.rooms), [])
self.points.extend(self.room_transfer_points)
for room in self.rooms:
room.build_connections()
pass # room.build_connections()
print('%d points' % len(self.points))
print('%d room transfer points' % len(self.no_room_points))
print()
print('%d room transfer points' % len(self.room_transfer_points))
def collect_rooms(self):
accessibles = self.level.geometries.accessible
accessibles = assert_multipolygon(accessibles)
for geometry in accessibles:
GraphRoom(self, geometry)
room = GraphRoom(self, geometry)
if room.prepare_build():
self.rooms.append(room)
def create_doors(self):
doors = self.level.geometries.doors
@ -50,22 +55,33 @@ class GraphLevel():
for door in doors:
polygon = door.buffer(0.01, join_style=JOIN_STYLE.mitre)
center = door.centroid
center_point = GraphPoint(center.x, center.y, level=self)
num_points = 0
connected_rooms = set()
points = []
for room in self.rooms:
if not polygon.intersects(room.geometry):
continue
for subpolygon in assert_multipolygon(polygon.intersection(room.geometry)):
connected_rooms.add(room)
nearest_point = get_nearest_point(room.clear_geometry, subpolygon.centroid)
point = GraphPoint(nearest_point.x, nearest_point.y, room)
center_point.connect_to(point)
point.connect_to(center_point)
num_points += 1
room.points.append(point)
points.append(point)
if num_points < 2:
print('door with <2 num_points (%d) detected at (%.2f, %.2f)' % (num_points, center.x, center.y))
if len(points) < 2:
print('door with <2 points (%d) detected at (%.2f, %.2f)' % (num_points, center.x, center.y))
continue
center_point = GraphPoint(center.x, center.y, rooms=tuple(connected_rooms))
self.room_transfer_points.append(center_point)
for room in connected_rooms:
room.points.append(center_point)
for point in points:
center_point.connect_to(point)
point.connect_to(center_point)
def create_levelconnectors(self):
for levelconnector in self.level.levelconnectors.all():
@ -80,6 +96,7 @@ class GraphLevel():
if not point.within(room.clear_geometry):
point = get_nearest_point(room.clear_geometry, point)
point = GraphPoint(point.x, point.y, room)
room.points.append(point)
self.graph.add_levelconnector_point(levelconnector, point)
def draw_png(self, points=True, lines=True):
@ -98,12 +115,11 @@ class GraphLevel():
for point in self.points:
draw.ellipse(_ellipse_bbox(point.x, point.y, height), (200, 0, 0))
for point in self.no_room_points:
for point in self.room_transfer_points:
draw.ellipse(_ellipse_bbox(point.x, point.y, height), (0, 0, 255))
for point in self.points:
for point in self.room_transfer_points:
for otherpoint, connection in point.connections.items():
if otherpoint in self.graph.no_level_points:
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)

View file

@ -12,6 +12,7 @@ class Command(BaseCommand):
start = time.time()
graph = Graph()
graph.build()
print()
print('Built in %.4fs' % (time.time() - start))
start = time.time()

View file

@ -4,28 +4,17 @@ from django.utils.functional import cached_property
class GraphPoint():
def __init__(self, x, y, room=None, level=None, graph=None):
self.room = room
self.level = room.level if level is None and room is not None else level
self.graph = self.level.graph if graph is None and self.level is not None else graph
def __init__(self, x, y, room=None, rooms=None):
self.rooms = rooms if rooms is not None else [room]
self.x = x
self.y = y
self.xy = np.array((x, y))
# self.level = room.level
self.graph = self.rooms[0].graph
self.connections = {}
self.connections_in = {}
self.in_room_transfer_distances = None
if self.room is not None:
self.room.points.append(self)
elif self.level is not None:
self.level.no_room_points.append(self)
if self.level is not None:
self.level.points.append(self)
else:
self.graph.no_level_points.append(self)
self.graph.points.append(self)
@cached_property
def ellipse_bbox(self):

View file

@ -12,30 +12,27 @@ from c3nav.routing.utils.mpl import shapely_to_mpl
class GraphRoom():
def __init__(self, level, geometry, mpl_clear=None):
def __init__(self, level, geometry=None, mpl_clear=None):
self.level = level
self.graph = level.graph
self.geometry = geometry
self.points = []
self.clear_geometry = geometry.buffer(-0.3, join_style=JOIN_STYLE.mitre)
self.empty = self.clear_geometry.is_empty
self.router = Router()
if not self.empty:
self.level.rooms.append(self)
self.graph.rooms.append(self)
self.mpl_clear = mpl_clear
self.points = []
def prepare_build(self):
self.clear_geometry = self.geometry.buffer(-0.3, join_style=JOIN_STYLE.mitre)
if self.clear_geometry.is_empty:
return False
self.mpl_clear = shapely_to_mpl(self.clear_geometry.buffer(0.01, join_style=JOIN_STYLE.mitre))
self.mpl_stairs = ()
for stair_line in assert_multilinestring(self.level.level.geometries.stairs):
coords = tuple(stair_line.coords)
self.mpl_stairs += tuple((Path(part), coord_angle(*part)) for part in zip(coords[:-1], coords[1:]))
return True
def build_points(self):
original_geometry = self.geometry
@ -127,11 +124,13 @@ class GraphRoom():
if not self.mpl_clear.contains_point(coord):
return []
point = GraphPoint(coord[0], coord[1], self)
self.points.append(point)
return [point]
def build_connections(self):
i = 0
for point1, point2 in combinations(self.points, 2):
own_points = [point for point in self.points if point not in self.level.room_transfer_points]
for point1, point2 in combinations(own_points, 2):
path = Path(np.vstack((point1.xy, point2.xy)))
# lies within room
@ -159,4 +158,5 @@ class GraphRoom():
i += 1
def build_router(self):
self.router = Router()
self.router.build(self.points)