split route into connections

This commit is contained in:
Laura Klünder 2016-12-17 14:46:15 +01:00
parent 988c7b1d11
commit 4f847f4e49
5 changed files with 87 additions and 29 deletions

View file

@ -6,6 +6,3 @@ class GraphConnection():
self.from_point = from_point self.from_point = from_point
self.to_point = to_point self.to_point = to_point
self.distance = distance if distance is not None else abs(np.linalg.norm(from_point.xy - to_point.xy)) self.distance = distance if distance is not None else abs(np.linalg.norm(from_point.xy - to_point.xy))
def serialize(self):
return (self.distance, )

View file

@ -12,7 +12,7 @@ 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
from c3nav.routing.point import GraphPoint from c3nav.routing.point import GraphPoint
from c3nav.routing.route import GraphRouteSegment, LevelRouteSegment, NoRoute, RoomRouteSegment, Route from c3nav.routing.route import GraphRouteSegment, LevelRouteSegment, NoRoute, RoomRouteSegment, SegmentRoute
class Graph: class Graph:
@ -181,8 +181,8 @@ class Graph:
sparse_distances = empty_distances.copy() sparse_distances = empty_distances.copy()
sparse_levels = np.zeros(shape=(len(self.level_transfer_points),) * 2, dtype=np.int16) level_transfers = np.zeros(shape=(len(self.level_transfer_points),) * 2, dtype=np.int16)
sparse_levels[:] = -1 level_transfers[:] = -1
for i, level in enumerate(self.levels.values()): for i, level in enumerate(self.levels.values()):
routers.update(level.build_routers()) routers.update(level.build_routers())
@ -197,12 +197,12 @@ class Graph:
better = level_distances < sparse_distances better = level_distances < sparse_distances
sparse_distances[better.transpose()] = level_distances[better.transpose()] sparse_distances[better.transpose()] = level_distances[better.transpose()]
sparse_levels[better.transpose()] = i level_transfers[better.transpose()] = i
g_sparse = csgraph_from_dense(sparse_distances, null_value=np.inf) g_sparse = csgraph_from_dense(sparse_distances, null_value=np.inf)
shortest_paths, predecessors = shortest_path(g_sparse, return_predecessors=True) shortest_paths, predecessors = shortest_path(g_sparse, return_predecessors=True)
routers[self] = GraphRouter(shortest_paths, predecessors) routers[self] = GraphRouter(shortest_paths, predecessors, level_transfers)
return routers return routers
def get_location_points(self, location: Location): def get_location_points(self, location: Location):
@ -295,9 +295,10 @@ class Graph:
from_point, to_point = np.argwhere(shortest_paths == distance)[0] from_point, to_point = np.argwhere(shortest_paths == distance)[0]
from_point = o_points[from_point] from_point = o_points[from_point]
to_point = d_points[to_point] to_point = d_points[to_point]
best_route = Route((orig_room_transfers[level.room_transfer_points[from_point]], best_route = SegmentRoute((orig_room_transfers[level.room_transfer_points[from_point]],
LevelRouteSegment(level, routers, from_point, to_point), LevelRouteSegment(level, routers, from_point, to_point),
dest_room_transfers[level.room_transfer_points[to_point]]), distance=distance) dest_room_transfers[level.room_transfer_points[to_point]]),
distance=distance)
# 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
@ -327,9 +328,10 @@ class Graph:
from_point, to_point = np.argwhere(shortest_paths == distance)[0] from_point, to_point = np.argwhere(shortest_paths == distance)[0]
from_point = o_points[from_point] from_point = o_points[from_point]
to_point = d_points[to_point] to_point = d_points[to_point]
best_route = Route((orig_level_transfers[self.level_transfer_points[from_point]], best_route = SegmentRoute((orig_level_transfers[self.level_transfer_points[from_point]],
GraphRouteSegment(self, routers, from_point, to_point), GraphRouteSegment(self, routers, from_point, to_point),
dest_level_transfers[self.level_transfer_points[to_point]]), distance=distance) dest_level_transfers[self.level_transfer_points[to_point]]),
distance=distance)
return best_route return best_route
@ -395,9 +397,9 @@ class Graph:
segments.insert(0, all_room_transfers[room_transfer_i]) segments.insert(0, all_room_transfers[room_transfer_i])
else: else:
segments.append(all_room_transfers[room_transfer_i]) segments.append(all_room_transfers[room_transfer_i])
level_transfers[transfer_i] = Route(segments, distance) level_transfers[transfer_i] = SegmentRoute(segments, distance)
return level_transfers return level_transfers
GraphRouter = namedtuple('GraphRouter', ('shortest_paths', 'predecessors', )) GraphRouter = namedtuple('GraphRouter', ('shortest_paths', 'predecessors', 'level_transfers', ))

View file

@ -227,4 +227,4 @@ class GraphLevel():
return routers return routers
LevelRouter = namedtuple('LevelRouter', ('shortest_paths', 'predecessors', 'rooms_transfers', )) LevelRouter = namedtuple('LevelRouter', ('shortest_paths', 'predecessors', 'room_transfers', ))

View file

@ -9,6 +9,7 @@ from shapely.geometry import CAP_STYLE, JOIN_STYLE, LineString
from c3nav.mapdata.utils.geometry import assert_multilinestring, assert_multipolygon from c3nav.mapdata.utils.geometry import assert_multilinestring, assert_multipolygon
from c3nav.routing.area import GraphArea from c3nav.routing.area import GraphArea
from c3nav.routing.connection import GraphConnection
from c3nav.routing.point import GraphPoint from c3nav.routing.point import GraphPoint
from c3nav.routing.utils.coords import coord_angle, get_coords_angles from c3nav.routing.utils.coords import coord_angle, get_coords_angles
from c3nav.routing.utils.mpl import shapely_to_mpl from c3nav.routing.utils.mpl import shapely_to_mpl
@ -218,5 +219,8 @@ class GraphRoom():
shortest_paths, predecessors = shortest_path(g_sparse, return_predecessors=True) shortest_paths, predecessors = shortest_path(g_sparse, return_predecessors=True)
return RoomRouter(shortest_paths, predecessors) return RoomRouter(shortest_paths, predecessors)
def get_connection(self, from_i, to_i):
return GraphConnection(self.graph.points[self.points[from_i]], self.graph.points[self.points[to_i]])
RoomRouter = namedtuple('RoomRouter', ('shortest_paths', 'predecessors', )) RoomRouter = namedtuple('RoomRouter', ('shortest_paths', 'predecessors', ))

View file

@ -1,22 +1,23 @@
from abc import ABC from abc import ABC, abstractmethod
import numpy as np import numpy as np
from django.utils.functional import cached_property from django.utils.functional import cached_property
class RouteSegment(ABC): class RouteSegment(ABC):
def __init__(self, router, from_point, to_point): def __init__(self, routers, router, from_point, to_point):
""" """
:param router: a Router (RoomRouter, GraphRouter, ) :param router: a Router (RoomRouter, GraphRouter, )
:param from_point: in-router index of first point :param from_point: in-router index of first point
:param to_point: in-router index of last point :param to_point: in-router index of last point
""" """
self.routers = routers
self.router = router self.router = router
self.from_point = int(from_point) self.from_point = int(from_point)
self.to_point = int(to_point) self.to_point = int(to_point)
def as_route(self): def as_route(self):
return Route([self]) return SegmentRoute([self])
def _get_points(self): def _get_points(self):
points = [self.to_point] points = [self.to_point]
@ -27,6 +28,10 @@ class RouteSegment(ABC):
points.append(current) points.append(current)
return tuple(reversed(points)) return tuple(reversed(points))
@abstractmethod
def get_connections(self):
pass
@cached_property @cached_property
def distance(self): def distance(self):
return self.router.shortest_paths[self.from_point, self.to_point] return self.router.shortest_paths[self.from_point, self.to_point]
@ -37,15 +42,17 @@ class RoomRouteSegment(RouteSegment):
""" """
Route segment within a Room Route segment within a Room
:param room: GraphRoom :param room: GraphRoom
:param router: RoomRouter
:param from_point: in-room index of first point
:param to_point: in-room index of last point
""" """
super().__init__(routers[room], from_point, to_point) super().__init__(routers, routers[room], from_point, to_point)
self.room = room self.room = room
self.global_from_point = room.points[from_point] self.global_from_point = room.points[from_point]
self.global_to_point = room.points[to_point] self.global_to_point = room.points[to_point]
def get_connections(self):
points = self._get_points()
return tuple(self.room.get_connection(from_point, to_point)
for from_point, to_point in zip(points[:-1], points[1:]))
def __repr__(self): def __repr__(self):
return ('<RoomRouteSegment in %r from points %d to %d with distance %f>' % return ('<RoomRouteSegment in %r from points %d to %d with distance %f>' %
(self.room, self.from_point, self.to_point, self.distance)) (self.room, self.from_point, self.to_point, self.distance))
@ -57,11 +64,26 @@ class LevelRouteSegment(RouteSegment):
Route segment within a Level (from room transfer point to room transfer point) Route segment within a Level (from room transfer point to room transfer point)
:param level: GraphLevel :param level: GraphLevel
""" """
super().__init__(routers[level], from_point, to_point) super().__init__(routers, routers[level], from_point, to_point)
self.level = level self.level = level
self.global_from_point = level.room_transfer_points[from_point] self.global_from_point = level.room_transfer_points[from_point]
self.global_to_point = level.room_transfer_points[to_point] self.global_to_point = level.room_transfer_points[to_point]
def split(self):
segments = []
points = self._get_points()
for from_point, to_point in zip(points[:-1], points[1:]):
room = self.level.rooms[self.router.room_transfers[from_point, to_point]]
global_from_point = self.level.room_transfer_points[from_point]
global_to_point = self.level.room_transfer_points[to_point]
segments.append(RoomRouteSegment(room, self.routers,
from_point=room.points.index(global_from_point),
to_point=room.points.index(global_to_point)))
return tuple(segments)
def get_connections(self):
return sum((segment.get_connections() for segment in self.split()), ())
def __repr__(self): def __repr__(self):
return ('<LevelRouteSegment in %r from points %d to %d with distance %f>' % return ('<LevelRouteSegment in %r from points %d to %d with distance %f>' %
(self.level, self.from_point, self.to_point, self.distance)) (self.level, self.from_point, self.to_point, self.distance))
@ -73,24 +95,57 @@ class GraphRouteSegment(RouteSegment):
Route segment within a Graph (from level transfer point to level transfer point) Route segment within a Graph (from level transfer point to level transfer point)
:param graph: Graph :param graph: Graph
""" """
super().__init__(routers[graph], from_point, to_point) super().__init__(routers, routers[graph], from_point, to_point)
self.graph = graph self.graph = graph
self.global_from_point = graph.level_transfer_points[from_point] self.global_from_point = graph.level_transfer_points[from_point]
self.global_to_point = graph.level_transfer_points[to_point] self.global_to_point = graph.level_transfer_points[to_point]
def split(self):
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]]
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,
from_point=level.room_transfer_points.index(global_from_point),
to_point=level.room_transfer_points.index(global_to_point)))
return tuple(segments)
def get_connections(self):
return sum((segment.get_connections() for segment in self.split()), ())
def __repr__(self): def __repr__(self):
return ('<GraphRouteSegment in %r from points %d to %d with distance %f>' % return ('<GraphRouteSegment in %r from points %d to %d with distance %f>' %
(self.graph, self.from_point, self.to_point, self.distance)) (self.graph, self.from_point, self.to_point, self.distance))
class Route: class SegmentRoute:
def __init__(self, segments, distance=None): def __init__(self, segments, distance=None):
self.segments = sum(((item.segments if isinstance(item, Route) else (item, )) for item in segments), ()) self.segments = sum(((item.segments if isinstance(item, SegmentRoute) else (item,))
for item in segments if item.from_point != item.to_point), ())
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.to_point = segments[-1].global_to_point
def __repr__(self):
return ('<SegmentedRoute (\n %s\n) distance=%f>' %
('\n '.join(repr(segment) for segment in self.segments), self.distance))
def split(self):
return Route(sum((segment.get_connections() for segment in self.segments), ()))
class Route:
def __init__(self, connections, distance=None):
self.connections = tuple(connections)
self.distance = sum(connection.distance for connection in self.connections)
self.from_point = connections[0].from_point
self.to_point = connections[-1].to_point
def __repr__(self): def __repr__(self):
return ('<Route (\n %s\n) distance=%f>' % return ('<Route (\n %s\n) distance=%f>' %
('\n '.join(repr(segment) for segment in self.segments), self.distance)) ('\n '.join(repr(connection) for connection in self.connections), self.distance))
class NoRoute: class NoRoute: