connect elevators and add ctypes elevator_up and elevator_down

This commit is contained in:
Laura Klünder 2016-12-18 00:26:00 +01:00
parent 6b0d3aeac2
commit 8a1f8bb290
6 changed files with 72 additions and 10 deletions

View file

@ -1,13 +1,14 @@
import os import os
import pickle import pickle
from collections import OrderedDict, namedtuple from collections import OrderedDict, namedtuple
from itertools import combinations
import numpy as np import numpy as np
from django.conf import settings from django.conf import settings
from scipy.sparse.csgraph._shortest_path import shortest_path from scipy.sparse.csgraph._shortest_path import shortest_path
from scipy.sparse.csgraph._tools import csgraph_from_dense 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.geometry import LevelConnector
from c3nav.mapdata.models.locations import AreaLocation, Location, LocationGroup, PointLocation from c3nav.mapdata.models.locations import AreaLocation, Location, LocationGroup, PointLocation
from c3nav.routing.level import GraphLevel from c3nav.routing.level import GraphLevel
@ -29,12 +30,15 @@ class Graph:
self.points = [] self.points = []
self.level_transfer_points = None self.level_transfer_points = None
self.elevatorlevel_points = None
# Building the Graph # Building the Graph
def build(self): def build(self):
self._built_level_transfer_points = [] self._built_level_transfer_points = []
self._built_levelconnector_points = {} self._built_levelconnector_points = {}
self._built_elevatorlevel_points = {}
for level in self.levels.values(): for level in self.levels.values():
level.build() level.build()
@ -45,6 +49,7 @@ class Graph:
# create connections between levels # create connections between levels
print() print()
self.connect_levelconnectors() self.connect_levelconnectors()
self.connect_elevators()
# finishing build: creating numpy arrays and convert everything else to tuples # finishing build: creating numpy arrays and convert everything else to tuples
self.points = tuple(set(self.points)) self.points = tuple(set(self.points))
@ -78,6 +83,9 @@ class Graph:
def add_levelconnector_point(self, levelconnector, point): def add_levelconnector_point(self, levelconnector, point):
self._built_levelconnector_points.setdefault(levelconnector.name, []).append(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): def connect_levelconnectors(self):
for levelconnector in LevelConnector.objects.all(): for levelconnector in LevelConnector.objects.all():
center = levelconnector.geometry.centroid center = levelconnector.geometry.centroid
@ -108,6 +116,30 @@ class Graph:
center_point.connect_to(point) center_point.connect_to(point)
point.connect_to(center_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 # Loading/Saving the Graph
def serialize(self): def serialize(self):
return ( return (
@ -273,9 +305,8 @@ class Graph:
for level in orig_levels} for level in orig_levels}
dest_room_transfer_points = {level: self._allowed_points_index(level.room_transfer_points, dest_room_transfers) dest_room_transfer_points = {level: self._allowed_points_index(level.room_transfer_points, dest_room_transfers)
for level in dest_levels} 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: if common_levels:
for level in common_levels: for level in common_levels:
o_points = orig_room_transfer_points[level] o_points = orig_room_transfer_points[level]
@ -305,13 +336,11 @@ class Graph:
# get reachable level transfer points and their distance # get reachable level transfer points and their distance
# as a dictionary: global transfer point index => Route # as a dictionary: global transfer point index => Route
orig_level_transfers = self._level_transfers(orig_levels, orig_room_transfers, routers, mode='orig') 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') dest_level_transfers = self._level_transfers(dest_levels, dest_room_transfers, routers, mode='dest')
print(orig_levels, dest_room_transfers, dest_level_transfers)
# get reachable leveltransfer points (points as level transfer point index within graph) # 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) 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) 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 # search a route within the whole graph
if True: if True:
@ -327,6 +356,7 @@ class Graph:
distance = shortest_paths.min() distance = shortest_paths.min()
# Is this route better than the previous ones? # Is this route better than the previous ones?
print('vialevels', distance, best_route.distance)
if distance < best_route.distance: if distance < best_route.distance:
# noinspection PyTypeChecker # noinspection PyTypeChecker
from_point, to_point = np.argwhere(shortest_paths == distance)[0] from_point, to_point = np.argwhere(shortest_paths == distance)[0]

View file

@ -57,6 +57,7 @@ class GraphLevel():
self.create_doors() self.create_doors()
self.create_levelconnectors() self.create_levelconnectors()
self.create_elevatorlevels()
self._built_points = sum((room._built_points for room in self.rooms), []) self._built_points = sum((room._built_points for room in self.rooms), [])
self._built_points.extend(self._built_room_transfer_points) self._built_points.extend(self._built_room_transfer_points)
@ -130,6 +131,28 @@ class GraphLevel():
room._built_points.append(point) room._built_points.append(point)
self.graph.add_levelconnector_point(levelconnector, 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): def collect_arealocations(self):
self._built_arealocations = {} self._built_arealocations = {}
for arealocation in self.level.arealocations.all(): for arealocation in self.level.arealocations.all():
@ -160,6 +183,8 @@ class GraphLevel():
'': (50, 200, 0), '': (50, 200, 0),
'steps_up': (255, 50, 50), 'steps_up': (255, 50, 50),
'steps_down': (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): def draw_png(self, points=True, lines=True):

View file

@ -55,6 +55,7 @@ class GraphRoom():
return False return False
self._built_points = [] 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_clear = shapely_to_mpl(self.clear_geometry.buffer(0.01, join_style=JOIN_STYLE.mitre))
self.mpl_stairs = () self.mpl_stairs = ()
@ -186,6 +187,9 @@ class GraphRoom():
return [point] return [point]
def build_connections(self): def build_connections(self):
if self._built_is_elevatorlevel:
return
for area in self.areas: for area in self.areas:
area.build_connections() area.build_connections()
@ -221,6 +225,7 @@ class GraphRoom():
# Routing # Routing
def build_router(self, allowed_ctypes): def build_router(self, allowed_ctypes):
ctypes = tuple(i for i, ctype in enumerate(self.ctypes) if ctype in 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' % cache_key = ('c3nav__graph__roomrouter__%s__%s__%s' %
(self.graph.mtime, self.i, ','.join(str(i) for i in ctypes))) (self.graph.mtime, self.i, ','.join(str(i) for i in ctypes)))
roomrouter = cache.get(cache_key) roomrouter = cache.get(cache_key)

View file

@ -27,11 +27,10 @@ class Route:
if point.level and point.level != level: if point.level and point.level != level:
routeparts.append(RoutePart(level, connections)) routeparts.append(RoutePart(level, connections))
level = point.level level = point.level
connections = [] connections = [connection]
if connections: if connections:
routeparts.append(RoutePart(level, connections)) routeparts.append(RoutePart(level, connections))
print(routeparts)
return tuple(routeparts) return tuple(routeparts)

View file

@ -105,7 +105,7 @@ class GraphRouteSegment(RouteSegment):
segments = [] segments = []
points = self._get_points() points = self._get_points()
for from_point, to_point in zip(points[:-1], points[1:]): 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_from_point = self.graph.level_transfer_points[from_point]
global_to_point = self.graph.level_transfer_points[to_point] global_to_point = self.graph.level_transfer_points[to_point]
segments.append(LevelRouteSegment(level, self.routers, segments.append(LevelRouteSegment(level, self.routers,
@ -128,6 +128,8 @@ class SegmentRoute:
self.distance = sum(segment.distance for segment in self.segments) self.distance = sum(segment.distance for segment in self.segments)
self.from_point = segments[0].global_from_point self.from_point = segments[0].global_from_point
self.to_point = segments[-1].global_to_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): def __repr__(self):
return ('<SegmentedRoute (\n %s\n) distance=%f>' % return ('<SegmentedRoute (\n %s\n) distance=%f>' %

View file

@ -42,7 +42,8 @@ def main(request, origin=None, destination=None):
route = None route = None
if origin and destination: if origin and destination:
graph = Graph.load() 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() route = route.split()
print(route) print(route)