diff --git a/src/c3nav/routing/graph.py b/src/c3nav/routing/graph.py index 91d23fb5..faeb5168 100644 --- a/src/c3nav/routing/graph.py +++ b/src/c3nav/routing/graph.py @@ -1,13 +1,14 @@ import os import pickle from collections import OrderedDict, namedtuple +from itertools import combinations import numpy as np from django.conf import settings from scipy.sparse.csgraph._shortest_path import shortest_path from scipy.sparse.csgraph._tools import csgraph_from_dense -from c3nav.mapdata.models import Level +from c3nav.mapdata.models import Elevator, Level from c3nav.mapdata.models.geometry import LevelConnector from c3nav.mapdata.models.locations import AreaLocation, Location, LocationGroup, PointLocation from c3nav.routing.level import GraphLevel @@ -29,12 +30,15 @@ class Graph: self.points = [] self.level_transfer_points = None + self.elevatorlevel_points = None # Building the Graph def build(self): self._built_level_transfer_points = [] self._built_levelconnector_points = {} + self._built_elevatorlevel_points = {} + for level in self.levels.values(): level.build() @@ -45,6 +49,7 @@ class Graph: # create connections between levels print() self.connect_levelconnectors() + self.connect_elevators() # finishing build: creating numpy arrays and convert everything else to tuples self.points = tuple(set(self.points)) @@ -78,6 +83,9 @@ class Graph: def add_levelconnector_point(self, levelconnector, point): self._built_levelconnector_points.setdefault(levelconnector.name, []).append(point) + def add_elevatorlevel_point(self, elevatorlevel, point): + self._built_elevatorlevel_points[elevatorlevel.name] = point + def connect_levelconnectors(self): for levelconnector in LevelConnector.objects.all(): center = levelconnector.geometry.centroid @@ -108,6 +116,30 @@ class Graph: center_point.connect_to(point) point.connect_to(center_point) + def connect_elevators(self): + for elevator in Elevator.objects.all(): + elevatorlevels = tuple(elevator.elevatorlevels.all()) + for level1, level2 in combinations(elevatorlevels, 2): + point1 = self._built_elevatorlevel_points[level1.name] + point2 = self._built_elevatorlevel_points[level2.name] + + center_point = GraphPoint((point1.x+point2.x)/2, (point1.y+point2.y)/2, None) + self.points.append(center_point) + self._built_level_transfer_points.append(center_point) + + for room in (point1.room, point2.room): + room._built_points.append(center_point) + room.level._built_room_transfer_points.append(center_point) + room.level._built_points.append(center_point) + + direction_up = level2.level.altitude > level1.level.altitude + + point1.connect_to(center_point, ctype=('elevator_up' if direction_up else 'elevator_down')) + center_point.connect_to(point2, ctype=('elevator_up' if direction_up else 'elevator_down')) + + point2.connect_to(center_point, ctype=('elevator_down' if direction_up else 'elevator_up')) + center_point.connect_to(point1, ctype=('elevator_down' if direction_up else 'elevator_up')) + # Loading/Saving the Graph def serialize(self): return ( @@ -273,9 +305,8 @@ class Graph: for level in orig_levels} dest_room_transfer_points = {level: self._allowed_points_index(level.room_transfer_points, dest_room_transfers) for level in dest_levels} - print(dest_room_transfer_points) - # if the points have common rooms, search for routes within thos levels + # if the points have common rooms, search for routes within those levels if common_levels: for level in common_levels: o_points = orig_room_transfer_points[level] @@ -305,13 +336,11 @@ class Graph: # get reachable level transfer points and their distance # as a dictionary: global transfer point index => Route orig_level_transfers = self._level_transfers(orig_levels, orig_room_transfers, routers, mode='orig') - dest_level_transfers = self._level_transfers(orig_levels, dest_room_transfers, routers, mode='dest') - print(orig_levels, dest_room_transfers, dest_level_transfers) + dest_level_transfers = self._level_transfers(dest_levels, dest_room_transfers, routers, mode='dest') # get reachable leveltransfer points (points as level transfer point index within graph) orig_level_transfer_points = self._allowed_points_index(self.level_transfer_points, orig_level_transfers) dest_level_transfer_points = self._allowed_points_index(self.level_transfer_points, dest_level_transfers) - print(dest_level_transfer_points) # search a route within the whole graph if True: @@ -327,6 +356,7 @@ class Graph: distance = shortest_paths.min() # Is this route better than the previous ones? + print('vialevels', distance, best_route.distance) if distance < best_route.distance: # noinspection PyTypeChecker from_point, to_point = np.argwhere(shortest_paths == distance)[0] diff --git a/src/c3nav/routing/level.py b/src/c3nav/routing/level.py index d87c6aed..d72ed11c 100644 --- a/src/c3nav/routing/level.py +++ b/src/c3nav/routing/level.py @@ -57,6 +57,7 @@ class GraphLevel(): self.create_doors() self.create_levelconnectors() + self.create_elevatorlevels() self._built_points = sum((room._built_points for room in self.rooms), []) self._built_points.extend(self._built_room_transfer_points) @@ -130,6 +131,28 @@ class GraphLevel(): room._built_points.append(point) self.graph.add_levelconnector_point(levelconnector, point) + def create_elevatorlevels(self): + for elevatorlevel in self.level.elevatorlevels.all(): + center = elevatorlevel.geometry.centroid + mpl_elevatorlevel = shapely_to_mpl(elevatorlevel.geometry) + for room in self.rooms: + if not room.mpl_clear.contains_point(center.coords[0]): + continue + + room._built_is_elevatorlevel = True + + points = [point for point in room._built_points if mpl_elevatorlevel.contains_point(point.xy)] + if not points: + print('elevatorlevel %s has 0 points!' % (elevatorlevel.name)) + break + elif len(points) > 1: + print('elevatorlevel %s has > 2 points!' % (elevatorlevel.name)) + break + + point = points[0] + self.graph.add_elevatorlevel_point(elevatorlevel, point) + break + def collect_arealocations(self): self._built_arealocations = {} for arealocation in self.level.arealocations.all(): @@ -160,6 +183,8 @@ class GraphLevel(): '': (50, 200, 0), 'steps_up': (255, 50, 50), 'steps_down': (255, 50, 50), + 'elevator_up': (200, 0, 200), + 'elevator_down': (200, 0, 200), } def draw_png(self, points=True, lines=True): diff --git a/src/c3nav/routing/room.py b/src/c3nav/routing/room.py index a3ef3238..84ad9c09 100644 --- a/src/c3nav/routing/room.py +++ b/src/c3nav/routing/room.py @@ -55,6 +55,7 @@ class GraphRoom(): return False self._built_points = [] + self._built_is_elevatorlevel = False self.mpl_clear = shapely_to_mpl(self.clear_geometry.buffer(0.01, join_style=JOIN_STYLE.mitre)) self.mpl_stairs = () @@ -186,6 +187,9 @@ class GraphRoom(): return [point] def build_connections(self): + if self._built_is_elevatorlevel: + return + for area in self.areas: area.build_connections() @@ -221,6 +225,7 @@ class GraphRoom(): # Routing def build_router(self, allowed_ctypes): ctypes = tuple(i for i, ctype in enumerate(self.ctypes) if ctype in allowed_ctypes) + print(self.ctypes) cache_key = ('c3nav__graph__roomrouter__%s__%s__%s' % (self.graph.mtime, self.i, ','.join(str(i) for i in ctypes))) roomrouter = cache.get(cache_key) diff --git a/src/c3nav/routing/route.py b/src/c3nav/routing/route.py index c14d033f..c701d88a 100644 --- a/src/c3nav/routing/route.py +++ b/src/c3nav/routing/route.py @@ -27,11 +27,10 @@ class Route: if point.level and point.level != level: routeparts.append(RoutePart(level, connections)) level = point.level - connections = [] + connections = [connection] if connections: routeparts.append(RoutePart(level, connections)) - print(routeparts) return tuple(routeparts) diff --git a/src/c3nav/routing/routesegments.py b/src/c3nav/routing/routesegments.py index d2901099..e902587a 100644 --- a/src/c3nav/routing/routesegments.py +++ b/src/c3nav/routing/routesegments.py @@ -105,7 +105,7 @@ class GraphRouteSegment(RouteSegment): segments = [] points = self._get_points() for from_point, to_point in zip(points[:-1], points[1:]): - level = self.graph.levels[self.router.level_transfers[from_point, to_point]] + level = tuple(self.graph.levels.values())[self.router.level_transfers[from_point, to_point]] global_from_point = self.graph.level_transfer_points[from_point] global_to_point = self.graph.level_transfer_points[to_point] segments.append(LevelRouteSegment(level, self.routers, @@ -128,6 +128,8 @@ class SegmentRoute: self.distance = sum(segment.distance for segment in self.segments) self.from_point = segments[0].global_from_point self.to_point = segments[-1].global_to_point + self.global_from_point = self.from_point + self.global_to_point = self.to_point def __repr__(self): return ('' % diff --git a/src/c3nav/site/views.py b/src/c3nav/site/views.py index 2c727ed4..40456766 100644 --- a/src/c3nav/site/views.py +++ b/src/c3nav/site/views.py @@ -42,7 +42,8 @@ def main(request, origin=None, destination=None): route = None if origin and destination: graph = Graph.load() - route = graph.get_route(origin, destination, ('', 'steps_down', 'steps_up')) + route = graph.get_route(origin, destination, ('', 'steps_down', 'steps_up', 'elevator_down', 'elevator_up')) + print(route) route = route.split() print(route)