connect elevators and add ctypes elevator_up and elevator_down
This commit is contained in:
parent
6b0d3aeac2
commit
8a1f8bb290
6 changed files with 72 additions and 10 deletions
|
@ -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]
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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>' %
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue