split route into connections
This commit is contained in:
parent
988c7b1d11
commit
4f847f4e49
5 changed files with 87 additions and 29 deletions
|
@ -6,6 +6,3 @@ class GraphConnection():
|
|||
self.from_point = from_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))
|
||||
|
||||
def serialize(self):
|
||||
return (self.distance, )
|
||||
|
|
|
@ -12,7 +12,7 @@ from c3nav.mapdata.models.geometry import LevelConnector
|
|||
from c3nav.mapdata.models.locations import AreaLocation, Location, LocationGroup, PointLocation
|
||||
from c3nav.routing.level import GraphLevel
|
||||
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:
|
||||
|
@ -181,8 +181,8 @@ class Graph:
|
|||
|
||||
sparse_distances = empty_distances.copy()
|
||||
|
||||
sparse_levels = np.zeros(shape=(len(self.level_transfer_points),) * 2, dtype=np.int16)
|
||||
sparse_levels[:] = -1
|
||||
level_transfers = np.zeros(shape=(len(self.level_transfer_points),) * 2, dtype=np.int16)
|
||||
level_transfers[:] = -1
|
||||
|
||||
for i, level in enumerate(self.levels.values()):
|
||||
routers.update(level.build_routers())
|
||||
|
@ -197,12 +197,12 @@ class Graph:
|
|||
|
||||
better = level_distances < sparse_distances
|
||||
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)
|
||||
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
|
||||
|
||||
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 = o_points[from_point]
|
||||
to_point = d_points[to_point]
|
||||
best_route = Route((orig_room_transfers[level.room_transfer_points[from_point]],
|
||||
LevelRouteSegment(level, routers, from_point, to_point),
|
||||
dest_room_transfers[level.room_transfer_points[to_point]]), distance=distance)
|
||||
best_route = SegmentRoute((orig_room_transfers[level.room_transfer_points[from_point]],
|
||||
LevelRouteSegment(level, routers, from_point, to_point),
|
||||
dest_room_transfers[level.room_transfer_points[to_point]]),
|
||||
distance=distance)
|
||||
|
||||
# get reachable level transfer points and their distance
|
||||
# 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 = o_points[from_point]
|
||||
to_point = d_points[to_point]
|
||||
best_route = Route((orig_level_transfers[self.level_transfer_points[from_point]],
|
||||
GraphRouteSegment(self, routers, from_point, to_point),
|
||||
dest_level_transfers[self.level_transfer_points[to_point]]), distance=distance)
|
||||
best_route = SegmentRoute((orig_level_transfers[self.level_transfer_points[from_point]],
|
||||
GraphRouteSegment(self, routers, from_point, to_point),
|
||||
dest_level_transfers[self.level_transfer_points[to_point]]),
|
||||
distance=distance)
|
||||
|
||||
return best_route
|
||||
|
||||
|
@ -395,9 +397,9 @@ class Graph:
|
|||
segments.insert(0, all_room_transfers[room_transfer_i])
|
||||
else:
|
||||
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
|
||||
|
||||
|
||||
GraphRouter = namedtuple('GraphRouter', ('shortest_paths', 'predecessors', ))
|
||||
GraphRouter = namedtuple('GraphRouter', ('shortest_paths', 'predecessors', 'level_transfers', ))
|
||||
|
|
|
@ -227,4 +227,4 @@ class GraphLevel():
|
|||
return routers
|
||||
|
||||
|
||||
LevelRouter = namedtuple('LevelRouter', ('shortest_paths', 'predecessors', 'rooms_transfers', ))
|
||||
LevelRouter = namedtuple('LevelRouter', ('shortest_paths', 'predecessors', 'room_transfers', ))
|
||||
|
|
|
@ -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.routing.area import GraphArea
|
||||
from c3nav.routing.connection import GraphConnection
|
||||
from c3nav.routing.point import GraphPoint
|
||||
from c3nav.routing.utils.coords import coord_angle, get_coords_angles
|
||||
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)
|
||||
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', ))
|
||||
|
|
|
@ -1,22 +1,23 @@
|
|||
from abc import ABC
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
import numpy as np
|
||||
from django.utils.functional import cached_property
|
||||
|
||||
|
||||
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 from_point: in-router index of first point
|
||||
:param to_point: in-router index of last point
|
||||
"""
|
||||
self.routers = routers
|
||||
self.router = router
|
||||
self.from_point = int(from_point)
|
||||
self.to_point = int(to_point)
|
||||
|
||||
def as_route(self):
|
||||
return Route([self])
|
||||
return SegmentRoute([self])
|
||||
|
||||
def _get_points(self):
|
||||
points = [self.to_point]
|
||||
|
@ -27,6 +28,10 @@ class RouteSegment(ABC):
|
|||
points.append(current)
|
||||
return tuple(reversed(points))
|
||||
|
||||
@abstractmethod
|
||||
def get_connections(self):
|
||||
pass
|
||||
|
||||
@cached_property
|
||||
def distance(self):
|
||||
return self.router.shortest_paths[self.from_point, self.to_point]
|
||||
|
@ -37,15 +42,17 @@ class RoomRouteSegment(RouteSegment):
|
|||
"""
|
||||
Route segment within a Room
|
||||
: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.global_from_point = room.points[from_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):
|
||||
return ('<RoomRouteSegment in %r from points %d to %d with distance %f>' %
|
||||
(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)
|
||||
:param level: GraphLevel
|
||||
"""
|
||||
super().__init__(routers[level], from_point, to_point)
|
||||
super().__init__(routers, routers[level], from_point, to_point)
|
||||
self.level = level
|
||||
self.global_from_point = level.room_transfer_points[from_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):
|
||||
return ('<LevelRouteSegment in %r from points %d to %d with distance %f>' %
|
||||
(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)
|
||||
:param graph: Graph
|
||||
"""
|
||||
super().__init__(routers[graph], from_point, to_point)
|
||||
super().__init__(routers, routers[graph], from_point, to_point)
|
||||
self.graph = graph
|
||||
self.global_from_point = graph.level_transfer_points[from_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):
|
||||
return ('<GraphRouteSegment in %r from points %d to %d with distance %f>' %
|
||||
(self.graph, self.from_point, self.to_point, self.distance))
|
||||
|
||||
|
||||
class Route:
|
||||
class SegmentRoute:
|
||||
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.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):
|
||||
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:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue