route descriptions

This commit is contained in:
Laura Klünder 2016-12-19 15:11:11 +01:00
parent 1e46ee10ae
commit b669e75af1
10 changed files with 359 additions and 140 deletions

View file

@ -1,5 +1,7 @@
import copy
import numpy as np
from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _
from c3nav.mapdata.utils.misc import get_dimensions
@ -11,31 +13,32 @@ class Route:
self.from_point = connections[0].from_point
self.to_point = connections[-1].to_point
self.routeparts = None
def __repr__(self):
return ('<Route (\n %s\n) distance=%f>' %
('\n '.join(repr(connection) for connection in self.connections), self.distance))
@cached_property
def routeparts(self):
def create_routeparts(self):
routeparts = []
connections = []
add_connections = []
level = self.connections[0].from_point.level
for connection in self.connections:
connections.append(connection)
connections.append(RouteLine(connection))
point = connection.to_point
if point.level and point.level != level:
if routeparts:
routeparts[-1].connections.extend(connections[:1])
routeparts[-1].lines.extend(connections[:1])
routeparts.append(RoutePart(level, add_connections+connections))
level = point.level
add_connections = connections[-3:]
add_connections = [copy.copy(line) for line in connections[-3:]]
connections = []
if connections:
if connections or add_connections:
if routeparts:
routeparts[-1].connections.extend(connections[:1])
routeparts[-1].lines.extend(connections[:1])
routeparts.append(RoutePart(level, add_connections+connections))
routeparts = [routepart for routepart in routeparts if not routepart.level.intermediate]
@ -43,26 +46,147 @@ class Route:
for routepart in routeparts:
routepart.render_svg_coordinates()
return tuple(routeparts)
self.describe(routeparts)
self.routeparts = routeparts
def describe(self, routeparts):
for i, routepart in enumerate(routeparts):
for j, line in enumerate(routepart.lines):
from_room = line.from_point.room
to_room = line.to_point.room
if i and not j:
line.ignore = True
line.turning = ''
if j:
line.angle_change = (line.angle - routepart.lines[j - 1].angle + 180) % 360 - 180
if 20 < line.angle_change <= 75:
line.turning = 'light_right'
elif -75 <= line.angle_change < -20:
line.turning = 'light_left'
elif 75 < line.angle_change:
line.turning = 'right'
elif line.angle_change < -75:
line.turning = 'left'
line.icon = line.ctype or line.turning
if from_room is None:
line.ignore = True
line.arrow = True
distance = line.distance
if line.ctype_main in ('stairs', 'escalator', 'elevator'):
line.description = {
'stairs_up': _('Go up the stairs.'),
'stairs_down': _('Go down the stairs.'),
'escalator_up': _('Take the escalator upwards.'),
'escalator_down': _('Take the escalator downwards.'),
'elevator_up': _('Take the elevator upwards.'),
'elevator_down': _('Take the elevator downwards.')
}.get(line.ctype)
if line.ctype_main == 'elevator':
if from_room is None or (to_room is None and from_room.level.level != routepart.level):
line.ignore = True
line.arrow = False
elif to_room is None:
if from_room is not None and from_room.level.level.intermediate:
line.ignore = True
if j > 0:
if routepart.lines[j-1].ctype_main == 'elevator':
line.arrow = False
if j+1 < len(routepart.lines):
if routepart.lines[j+1].to_point.room.level.level.intermediate:
line.ignore = True
if j+2 < len(routepart.lines):
if routepart.lines[j+2].ctype_main == 'elevator':
line.ignore = True
line.description = {
'left': _('Go through the door on the left.'),
'right': _('Go through the door on the right.'),
}.get(line.turning.split('_')[-1], _('Go through the door.'))
line.arrow = False
else:
if j > 0:
last = routepart.lines[j-1]
if last.can_merge_to_next:
if last.turning == '' and (line.turning == '' or last.desc_distance < 1):
last.ignore = True
last.arrow = False
distance += last.desc_distance
elif last.turning.endswith('right') and line.turning.endswith('right'):
last.ignore = True
last.arrow = False
line.turning = 'right'
distance += last.desc_distance
elif last.turning.endswith('left') and line.turning.endswith('left'):
last.ignore = True
last.arrow = False
line.turning = 'left'
distance += last.desc_distance
elif last.turning.endswith('left') and line.turning.endswith('left'):
last.ignore = True
last.arrow = False
line.turning = 'left'
distance += last.desc_distance
line.description = {
'light_left': _('Turn light to the left and continue for %(d).1f meters.') % {'d': distance},
'light_right': _('Turn light to the right and continue for %(d).1f meters.') % {'d': distance},
'left': _('Turn left and continue for %(d).1f meters.') % {'d': distance},
'right': _('Turn right and continue for %(d).1f meters.') % {'d': distance}
}.get(line.turning, _('Continue for %(d).1f meters.') % {'d': distance})
if distance < 0.2:
line.ignore = True
line.can_merge_to_next = True
line.desc_distance = distance
if line.ignore:
line.icon = None
line.description = None
line.desc_distance = None
line.can_merge_to_next = False
if line.arrow is None:
line.arrow = not line.ignore
last_lines = [line for line in routepart.lines if line.ctype_main != 'elevator']
if len(last_lines) > 1:
last_lines[-1].arrow = True
class RoutePart:
def __init__(self, graphlevel, connections):
def __init__(self, graphlevel, lines):
self.graphlevel = graphlevel
self.level = graphlevel.level
self.connections = connections
self.lines = lines
def render_svg_coordinates(self):
svg_width, svg_height = get_dimensions()
points = (self.connections[0].from_point, ) + tuple(connection.to_point for connection in self.connections)
points = (self.lines[0].from_point,) + tuple(connection.to_point for connection in self.lines)
for point in points:
point.svg_x = point.x * 6
point.svg_y = (svg_height - point.y) * 6
x, y = zip(*((point.svg_x, point.svg_y) for point in points if point.level == self.graphlevel))
self.distance = sum(connection.distance for connection in self.connections)
self.distance = sum(connection.distance for connection in self.lines)
# bounds for rendering
self.svg_min_x = min(x) - 20
@ -89,10 +213,23 @@ class RoutePart:
class RouteLine:
def __init__(self, from_point, to_point, distance):
self.from_point = from_point
self.to_point = to_point
self.distance = distance
def __init__(self, connection):
self.from_point = connection.from_point
self.to_point = connection.to_point
self.distance = connection.distance
self.ctype = connection.ctype
self.angle = connection.angle
self.ctype_main = self.ctype.split('_')[0]
self.ctype_direction = self.ctype.split('_')[-1]
self.ignore = False
self.arrow = None
self.angle_change = None
self.can_merge_to_next = False
self.icon = None
self.description = None
class NoRoute: