more exceptiosn and edge cases
This commit is contained in:
parent
6508d05a3e
commit
25af1c9901
5 changed files with 84 additions and 14 deletions
|
@ -1,6 +1,7 @@
|
||||||
import re
|
import re
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
|
@ -290,6 +291,10 @@ class PointLocation(Location):
|
||||||
def location_id(self):
|
def location_id(self):
|
||||||
return 'c:%s:%d:%d' % (self.level.name, self.x*100, self.y*100)
|
return 'c:%s:%d:%d' % (self.level.name, self.x*100, self.y*100)
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def xy(self):
|
||||||
|
return np.array((self.x, self.y))
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def description(self):
|
def description(self):
|
||||||
from c3nav.routing.graph import Graph
|
from c3nav.routing.graph import Graph
|
||||||
|
|
6
src/c3nav/routing/exceptions.py
Normal file
6
src/c3nav/routing/exceptions.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
class NoRouteFound(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class AlreadyThere(Exception):
|
||||||
|
pass
|
|
@ -12,6 +12,7 @@ from c3nav.mapdata.models import Elevator, Level
|
||||||
from c3nav.mapdata.models.geometry import LevelConnector
|
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.connection import GraphConnection
|
from c3nav.routing.connection import GraphConnection
|
||||||
|
from c3nav.routing.exceptions import AlreadyThere, NoRouteFound
|
||||||
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 NoRoute, Route
|
from c3nav.routing.route import NoRoute, Route
|
||||||
|
@ -245,7 +246,9 @@ class Graph:
|
||||||
def get_location_points(self, location: Location, mode):
|
def get_location_points(self, location: Location, mode):
|
||||||
if isinstance(location, PointLocation):
|
if isinstance(location, PointLocation):
|
||||||
points = self.levels[location.level.name].connected_points(np.array((location.x, location.y)), mode)
|
points = self.levels[location.level.name].connected_points(np.array((location.x, location.y)), mode)
|
||||||
points, distances, ctypes = zip(*((point, distance, ctype)for point, (distance, ctype) in points.items()))
|
if not points:
|
||||||
|
return (), None, None
|
||||||
|
points, distances, ctypes = zip(*((point, distance, ctype) for point, (distance, ctype) in points.items()))
|
||||||
points = np.array(points)
|
points = np.array(points)
|
||||||
distances = np.array(distances)
|
distances = np.array(distances)
|
||||||
return points, distances, ctypes
|
return points, distances, ctypes
|
||||||
|
@ -266,11 +269,15 @@ class Graph:
|
||||||
orig_points_i, orig_distances, orig_ctypes = self.get_location_points(origin, 'orig')
|
orig_points_i, orig_distances, orig_ctypes = self.get_location_points(origin, 'orig')
|
||||||
dest_points_i, dest_distances, dest_ctypes = self.get_location_points(destination, 'dest')
|
dest_points_i, dest_distances, dest_ctypes = self.get_location_points(destination, 'dest')
|
||||||
|
|
||||||
|
if not orig_points_i or not dest_points_i:
|
||||||
|
raise NoRouteFound()
|
||||||
|
|
||||||
add_orig_point = origin if isinstance(origin, PointLocation) else None
|
add_orig_point = origin if isinstance(origin, PointLocation) else None
|
||||||
add_dest_point = destination if isinstance(destination, PointLocation) else None
|
add_dest_point = destination if isinstance(destination, PointLocation) else None
|
||||||
|
|
||||||
orig_points = self._get_points_by_i(orig_points_i)
|
orig_points = self._get_points_by_i(orig_points_i)
|
||||||
dest_points = self._get_points_by_i(dest_points_i)
|
dest_points = self._get_points_by_i(dest_points_i)
|
||||||
|
common_points = tuple(set(orig_points) & set(dest_points))
|
||||||
|
|
||||||
best_route = NoRoute
|
best_route = NoRoute
|
||||||
|
|
||||||
|
@ -282,6 +289,7 @@ class Graph:
|
||||||
dest_rooms = set(point.room for point in dest_points)
|
dest_rooms = set(point.room for point in dest_points)
|
||||||
common_rooms = orig_rooms & dest_rooms
|
common_rooms = orig_rooms & dest_rooms
|
||||||
|
|
||||||
|
# rooms are directly connectable
|
||||||
if add_orig_point and add_dest_point and common_rooms:
|
if add_orig_point and add_dest_point and common_rooms:
|
||||||
room = tuple(common_rooms)[0]
|
room = tuple(common_rooms)[0]
|
||||||
ctype = room.check_connection((add_orig_point.x, add_orig_point.y), (add_dest_point.x, add_dest_point.y))
|
ctype = room.check_connection((add_orig_point.x, add_orig_point.y), (add_dest_point.x, add_dest_point.y))
|
||||||
|
@ -290,6 +298,37 @@ class Graph:
|
||||||
to_point = GraphPoint(add_dest_point.x, add_dest_point.y, room)
|
to_point = GraphPoint(add_dest_point.x, add_dest_point.y, room)
|
||||||
return Route((GraphConnection(from_point, to_point, ctype=ctype), ))
|
return Route((GraphConnection(from_point, to_point, ctype=ctype), ))
|
||||||
|
|
||||||
|
if common_points:
|
||||||
|
# same location
|
||||||
|
if not add_orig_point and not add_dest_point:
|
||||||
|
raise AlreadyThere()
|
||||||
|
|
||||||
|
# points are connectable with only one via
|
||||||
|
best_point = None
|
||||||
|
best_distance = np.inf
|
||||||
|
for point in common_points:
|
||||||
|
distance = 0
|
||||||
|
if add_orig_point:
|
||||||
|
distance += abs(np.linalg.norm(add_orig_point.xy - point.xy))
|
||||||
|
if add_dest_point:
|
||||||
|
distance += abs(np.linalg.norm(add_dest_point.xy - point.xy))
|
||||||
|
if distance < best_distance:
|
||||||
|
best_distance = distance
|
||||||
|
best_point = point
|
||||||
|
|
||||||
|
connections = []
|
||||||
|
if add_orig_point:
|
||||||
|
from_point = GraphPoint(add_orig_point.x, add_orig_point.y, best_point.room)
|
||||||
|
ctype = orig_ctypes[tuple(orig_points_i).index(best_point.i)]
|
||||||
|
connections.append(GraphConnection(from_point, best_point, ctype=ctype))
|
||||||
|
|
||||||
|
if add_dest_point:
|
||||||
|
to_point = GraphPoint(add_dest_point.x, add_dest_point.y, best_point.room)
|
||||||
|
ctype = dest_ctypes[tuple(dest_points_i).index(best_point.i)]
|
||||||
|
connections.append(GraphConnection(best_point, to_point, ctype=ctype))
|
||||||
|
|
||||||
|
return Route(connections)
|
||||||
|
|
||||||
# get origin points for each room (points as point index within room)
|
# get origin points for each room (points as point index within room)
|
||||||
orig_room_points = {room: self._allowed_points_index(room.points, orig_points_i) for room in orig_rooms}
|
orig_room_points = {room: self._allowed_points_index(room.points, orig_points_i) for room in orig_rooms}
|
||||||
dest_room_points = {room: self._allowed_points_index(room.points, dest_points_i) for room in dest_rooms}
|
dest_room_points = {room: self._allowed_points_index(room.points, dest_points_i) for room in dest_rooms}
|
||||||
|
@ -397,13 +436,14 @@ class Graph:
|
||||||
dest_level_transfers[self.level_transfer_points[to_point]]),
|
dest_level_transfers[self.level_transfer_points[to_point]]),
|
||||||
distance=distance)
|
distance=distance)
|
||||||
|
|
||||||
if best_route is not NoRoute:
|
if best_route is NoRoute:
|
||||||
orig_ctype = orig_ctypes[tuple(orig_points_i).index(best_route.from_point)] if add_orig_point else None
|
raise NoRouteFound()
|
||||||
dest_ctype = dest_ctypes[tuple(dest_points_i).index(best_route.to_point)] if add_dest_point else None
|
|
||||||
best_route = SegmentRouteWrapper(best_route, orig_point=add_orig_point, dest_point=add_dest_point,
|
orig_ctype = orig_ctypes[tuple(orig_points_i).index(best_route.from_point)] if add_orig_point else None
|
||||||
orig_ctype=orig_ctype, dest_ctype=dest_ctype)
|
dest_ctype = dest_ctypes[tuple(dest_points_i).index(best_route.to_point)] if add_dest_point else None
|
||||||
best_route = best_route.split()
|
best_route = SegmentRouteWrapper(best_route, orig_point=add_orig_point, dest_point=add_dest_point,
|
||||||
return best_route
|
orig_ctype=orig_ctype, dest_ctype=dest_ctype)
|
||||||
|
return best_route.split()
|
||||||
|
|
||||||
def _room_transfers(self, rooms, room_points, routers, mode):
|
def _room_transfers(self, rooms, room_points, routers, mode):
|
||||||
if mode not in ('orig', 'dest'):
|
if mode not in ('orig', 'dest'):
|
||||||
|
|
|
@ -64,6 +64,20 @@
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
{% if error == 'noroutefound' %}
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<strong>{% trans 'Sorry, no Route could be found.' %}</strong>
|
||||||
|
<p>
|
||||||
|
{% blocktrans %}
|
||||||
|
Your origin or your destination is not within an accessible area or there is no possible route between them.
|
||||||
|
{% endblocktrans %}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{% elif error == 'alreadythere' %}
|
||||||
|
<div class="alert alert-success">
|
||||||
|
<strong>{% trans 'Congratulations, you are already there!' %}</strong>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
{% if route %}
|
{% if route %}
|
||||||
{% include 'site/fragment_route.html' %}
|
{% include 'site/fragment_route.html' %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -11,6 +11,7 @@ from c3nav.mapdata.permissions import get_excludables_includables
|
||||||
from c3nav.mapdata.render.compose import composer
|
from c3nav.mapdata.render.compose import composer
|
||||||
from c3nav.mapdata.utils.cache import get_levels_cached
|
from c3nav.mapdata.utils.cache import get_levels_cached
|
||||||
from c3nav.mapdata.utils.misc import get_dimensions
|
from c3nav.mapdata.utils.misc import get_dimensions
|
||||||
|
from c3nav.routing.exceptions import AlreadyThere, NoRouteFound
|
||||||
from c3nav.routing.graph import Graph
|
from c3nav.routing.graph import Graph
|
||||||
|
|
||||||
ctype_mapping = {
|
ctype_mapping = {
|
||||||
|
@ -181,13 +182,17 @@ def main(request, location=None, origin=None, destination=None):
|
||||||
nonpublic = ':nonpublic' in include
|
nonpublic = ':nonpublic' in include
|
||||||
|
|
||||||
graph = Graph.load()
|
graph = Graph.load()
|
||||||
route = graph.get_route(origin, destination, allowed_ctypes, public=public, nonpublic=nonpublic,
|
|
||||||
avoid=avoid-set(':public'), include=include-set(':nonpublic'))
|
|
||||||
route.create_routeparts()
|
|
||||||
|
|
||||||
ctx.update({
|
try:
|
||||||
'route': route,
|
route = graph.get_route(origin, destination, allowed_ctypes, public=public, nonpublic=nonpublic,
|
||||||
})
|
avoid=avoid-set(':public'), include=include-set(':nonpublic'))
|
||||||
|
except NoRouteFound:
|
||||||
|
ctx.update({'error': 'noroutefound'})
|
||||||
|
except AlreadyThere:
|
||||||
|
ctx.update({'error': 'alreadythere'})
|
||||||
|
else:
|
||||||
|
route.create_routeparts()
|
||||||
|
ctx.update({'route': route})
|
||||||
|
|
||||||
response = render(request, 'site/main.html', ctx)
|
response = render(request, 'site/main.html', ctx)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue