team-3/src/c3nav/routing/route.py
2017-12-11 16:40:32 +01:00

127 lines
4.4 KiB
Python

# flake8: noqa
import copy
from collections import OrderedDict, deque
import numpy as np
from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _
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:
def __init__(self, router, origin, destination, distance, path_nodes, origin_addition, destination_addition):
self.router = router
self.origin = origin
self.destination = destination
self.distance = distance
self.path_nodes = path_nodes
self.origin_addition = origin_addition
self.destination_addition = destination_addition
def serialize(self, locations):
nodes = [[node, None] for node in self.path_nodes]
if self.origin_addition and any(self.origin_addition):
nodes.insert(0, (self.origin_addition[0], None))
nodes[1][1] = self.origin_addition[1]
if self.destination_addition and any(self.destination_addition):
nodes.append(self.destination_addition)
items = deque()
last_node = None
last_item = None
distance = 0
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)
if edge:
distance += edge.distance
items.append(item)
last_item = item
last_node = node
# 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:
item.descriptions.append(item.waytype.description_up)
else:
item.descriptions.append(item.waytype.description)
elif item.new_space:
pass # todo: custom space transition descriptions
items[-1].descriptions.append(_('You have reached your destination.'))
return OrderedDict((
('origin', describe_location(self.origin, locations)),
('destination', describe_location(self.destination, locations)),
('distance', round(distance, 2)),
('items', tuple(item.serialize(locations=locations) for item in items)),
))
class RouteItem:
def __init__(self, route, node, edge, last_item):
self.route = route
self.node = node
self.edge = edge
self.last_item = last_item
self.descriptions = []
@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]
@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):
result = OrderedDict((
('id', self.node.pk),
('coordinates', (self.node.x, self.node.y, self.node.altitude)),
('waytype', (self.route.router.waytypes[self.edge.waytype].serialize(detailed=False)
if self.edge and self.edge.waytype else None)),
))
if self.waytype:
result['waytype'] = self.waytype.serialize(detailed=False)
if self.new_space:
result['space'] = describe_location(self.space, locations)
if self.new_level:
result['level'] = describe_location(self.level, locations)
result['descriptions'] = self.descriptions
return result
class NoRoute:
distance = np.inf