team-3/src/c3nav/routing/route.py

128 lines
4.4 KiB
Python
Raw Normal View History

# flake8: noqa
2016-12-19 15:11:11 +01:00
import copy
2017-11-27 15:01:58 +01:00
from collections import OrderedDict, deque
2016-12-19 15:11:11 +01:00
2016-12-17 13:24:42 +01:00
import numpy as np
2017-11-27 15:41:25 +01:00
from django.utils.functional import cached_property
2016-12-19 15:11:11 +01:00
from django.utils.translation import ugettext_lazy as _
2016-12-17 13:24:42 +01:00
2016-12-17 14:46:15 +01:00
def describe_location(location, locations):
if location.can_describe:
final_location = locations.get(location.pk)
if final_location is not None:
location = final_location
else:
location.can_describe = False
return location.serialize(detailed=False, describe_only=True, simple_geometry=True)
class Route:
2017-11-28 23:25:56 +01:00
def __init__(self, router, origin, destination, distance, path_nodes, origin_addition, destination_addition):
2017-11-27 15:01:58 +01:00
self.router = router
self.origin = origin
self.destination = destination
self.distance = distance
self.path_nodes = path_nodes
2017-11-28 23:25:56 +01:00
self.origin_addition = origin_addition
self.destination_addition = destination_addition
2016-12-19 15:11:11 +01:00
def serialize(self, locations):
2017-11-28 23:25:56 +01:00
nodes = [[node, None] for node in self.path_nodes]
2017-11-28 23:34:11 +01:00
if self.origin_addition and any(self.origin_addition):
2017-11-28 23:25:56 +01:00
nodes.insert(0, (self.origin_addition[0], None))
nodes[1][1] = self.origin_addition[1]
2017-11-29 00:00:42 +01:00
if self.destination_addition and any(self.destination_addition):
2017-11-28 23:25:56 +01:00
nodes.append(self.destination_addition)
2017-11-27 15:01:58 +01:00
items = deque()
last_node = None
last_item = None
2017-11-27 16:49:12 +01:00
distance = 0
2017-11-28 23:25:56 +01:00
for i, (node, edge) in enumerate(nodes):
if edge is None:
edge = self.router.edges[last_node, node] if last_node else None
node_obj = self.router.nodes[node] if isinstance(node, (int, np.int32, np.int64)) else node
item = RouteItem(self, node_obj, edge, last_item)
2017-11-27 16:49:12 +01:00
if edge:
distance += edge.distance
2017-11-27 15:01:58 +01:00
items.append(item)
last_item = item
last_node = node
2017-12-11 16:23:54 +01:00
# descriptions for waytypes
next_item = None
for item in reversed(items):
if item.waytype:
if item.waytype.join_edges and next_item and next_item.waytype == item.waytype:
continue
if item.waytype.up_separate and item.edge.rise > 0:
2017-12-11 16:39:58 +01:00
item.descriptions.append(item.waytype.description_up)
2017-12-11 16:23:54 +01:00
else:
2017-12-11 16:39:58 +01:00
item.descriptions.append(item.waytype.description)
2017-12-11 16:23:54 +01:00
elif item.new_space:
2017-12-11 16:33:36 +01:00
pass # todo: custom space transition descriptions
2017-12-11 16:39:58 +01:00
items[-1].descriptions.append(_('You have reached your destination.'))
2017-12-11 16:23:54 +01:00
2016-12-29 20:06:57 +01:00
return OrderedDict((
('origin', describe_location(self.origin, locations)),
2017-11-28 00:39:02 +01:00
('destination', describe_location(self.destination, locations)),
2017-11-27 16:49:12 +01:00
('distance', round(distance, 2)),
('items', tuple(item.serialize(locations=locations) for item in items)),
2016-12-29 20:06:57 +01:00
))
2016-12-19 15:11:11 +01:00
2017-11-27 15:01:58 +01:00
class RouteItem:
def __init__(self, route, node, edge, last_item):
self.route = route
self.node = node
self.edge = edge
self.last_item = last_item
2017-12-11 16:33:36 +01:00
self.descriptions = []
2016-12-17 14:46:15 +01:00
2017-11-27 15:41:25 +01:00
@cached_property
def waytype(self):
if self.edge and self.edge.waytype:
return self.route.router.waytypes[self.edge.waytype]
@cached_property
def space(self):
return self.route.router.spaces[self.node.space]
@cached_property
def level(self):
return self.route.router.levels[self.space.level_id]
2017-12-11 16:23:54 +01:00
@cached_property
def new_space(self):
return not self.last_item or self.space.pk != self.last_item.space.pk
@cached_property
def new_level(self):
return not self.last_item or self.level.pk != self.last_item.level.pk
def serialize(self, locations):
2017-11-27 15:41:25 +01:00
result = OrderedDict((
2017-11-27 15:01:58 +01:00
('id', self.node.pk),
2017-11-27 16:42:35 +01:00
('coordinates', (self.node.x, self.node.y, self.node.altitude)),
2017-11-27 15:01:58 +01:00
('waytype', (self.route.router.waytypes[self.edge.waytype].serialize(detailed=False)
if self.edge and self.edge.waytype else None)),
2016-12-29 20:06:57 +01:00
))
2017-11-27 15:41:25 +01:00
if self.waytype:
result['waytype'] = self.waytype.serialize(detailed=False)
2017-12-11 16:23:54 +01:00
if self.new_space:
result['space'] = describe_location(self.space, locations)
2017-11-27 15:41:25 +01:00
2017-12-11 16:23:54 +01:00
if self.new_level:
result['level'] = describe_location(self.level, locations)
2017-12-11 16:23:54 +01:00
2017-12-11 16:39:58 +01:00
result['descriptions'] = self.descriptions
2017-11-27 15:41:25 +01:00
return result
2016-12-29 20:06:57 +01:00
2016-12-17 13:24:42 +01:00
class NoRoute:
distance = np.inf