route from/to custom locations

This commit is contained in:
Laura Klünder 2017-11-28 23:08:47 +01:00
parent f5ee24495e
commit b92c871bc2
5 changed files with 39 additions and 17 deletions

View file

@ -69,6 +69,8 @@ def assert_multilinestring(geometry: Union[LineString, MultiLineString, Geometry
def good_representative_point(geometry):
if isinstance(geometry, Point):
return geometry
c = geometry.centroid
x1, y1, x2, y2 = geometry.bounds
lines = (tuple(assert_multilinestring(LineString(((x1, c.y), (x2, c.y))).intersection(geometry))) +

View file

@ -227,6 +227,8 @@ def get_custom_location_for_request(slug: str, request):
class CustomLocation:
can_search = True
can_describe = True
access_restriction_id = None
def __init__(self, level, x, y):
x = round(x, 2)

View file

@ -1,25 +1,25 @@
from django import forms
from django.utils.translation import ugettext_lazy
from c3nav.mapdata.utils.locations import locations_for_request
from c3nav.mapdata.utils.locations import get_location_by_id_for_request
class RouteForm(forms.Form):
origin = forms.IntegerField(min_value=1)
destination = forms.IntegerField(min_value=1)
origin = forms.CharField()
destination = forms.CharField()
def __init__(self, *args, request=None, **kwargs):
self.request = request
super().__init__(*args, **kwargs)
def clean_origin(self):
try:
return locations_for_request(self.request)[self.cleaned_data['origin']]
except KeyError:
location = get_location_by_id_for_request(self.cleaned_data['origin'], self.request)
if location is None:
raise forms.ValidationError(ugettext_lazy('Unknown origin.'))
return location
def clean_destination(self):
try:
return locations_for_request(self.request)[self.cleaned_data['destination']]
except KeyError:
location = get_location_by_id_for_request(self.cleaned_data['destination'], self.request)
if location is None:
raise forms.ValidationError(ugettext_lazy('Unknown destination.'))
return location

View file

@ -16,6 +16,7 @@ from shapely.ops import unary_union
from c3nav.mapdata.models import AltitudeArea, Area, GraphEdge, Level, LocationGroup, Space, WayType
from c3nav.mapdata.models.geometry.space import POI
from c3nav.mapdata.utils.geometry import assert_multipolygon, good_representative_point
from c3nav.mapdata.utils.locations import CustomLocation
from c3nav.routing.route import Route
@ -122,7 +123,7 @@ class Router:
# todo: check waytypes here
for node in space_nodes:
line = LineString([(node.x, node.y), (fallback_node.x, fallback_node.y)])
if not clear_geom_prep.crosses(line):
if line.length < 5 and not clear_geom_prep.crosses(line):
area.fallback_nodes[node.i] = (
fallback_node,
RouterEdge(fallback_node, node, 0)
@ -139,10 +140,9 @@ class Router:
groups.setdefault(group.pk, {}).setdefault('pois', set()).add(poi.pk)
poi._prefetched_objects_cache = {}
poi = RouterPOI(poi)
poi = RouterPoint(poi)
altitudearea = space.altitudearea_for_point(poi.geometry)
poi_nodes = altitudearea.nodes_for_point(poi.geometry, all_nodes=nodes)
print(poi_nodes)
poi.nodes = set(i for i in poi_nodes.keys())
poi.nodes_addition = poi_nodes
pois[poi.pk] = poi
@ -212,11 +212,29 @@ class Router:
(self.spaces[pk] for pk in group.get('spaces', ())),
(self.areas[pk] for pk in group.get('areas', ()))
))
elif isinstance(location, CustomLocation):
point = Point(location.x, location.y)
location = RouterPoint(location)
space = self.space_for_point(location.level.pk, point)
altitudearea = space.altitudearea_for_point(point)
location_nodes = altitudearea.nodes_for_point(point, all_nodes=self.nodes)
location.nodes = set(i for i in location_nodes.keys())
location.nodes_addition = location_nodes
locations = tuple((location, ))
# todo: route from/to custom location
return RouterLocation(tuple(location for location in locations
if location is not None and (location.access_restriction_id is None or
location.access_restriction_id in permissions)))
def space_for_point(self, level, point):
# todo: only spaces that the user can see
point = Point(point.x, point.y)
level = self.levels[level]
for space in level.spaces:
if self.spaces[space].geometry_prep.intersects(point):
return self.spaces[space]
return self.spaces[min(level.spaces, key=lambda space: self.spaces[space].geometry.distance(point))]
def get_route(self, origin, destination, permissions=frozenset()):
# get possible origins and destinations
origins = self.get_locations(origin, permissions=permissions)
@ -289,14 +307,14 @@ class RouterSpace(BaseRouterProxy):
for area in self.altitudeareas:
if area.geometry_prep.intersects(point):
return area
return self.altitudareas[0]
return min(self.altitudeareas, key=lambda area: area.geometry.distance(point))
class RouterArea(BaseRouterProxy):
pass
class RouterPOI(BaseRouterProxy):
class RouterPoint(BaseRouterProxy):
pass
@ -331,7 +349,7 @@ class RouterAltitudeArea:
for node in self.nodes:
node = all_nodes[node]
line = LineString([(node.x, node.y), (point.x, point.y)])
if not self.clear_geometry_prep.crosses(line):
if line.length < 5 and not self.clear_geometry_prep.crosses(line):
nodes[node.i] = None
if not nodes:
nearest_node = min(tuple(all_nodes[node] for node in self.nodes),
@ -394,7 +412,7 @@ class RouterWayType:
class RouterLocation:
def __init__(self, locations=()):
self.locations = tuple(location for location in locations if locations)
self.locations = locations
@cached_property
def nodes(self):

View file

@ -218,7 +218,7 @@ c3nav = {
},
_route_loaded: function(data, nofly) {
var $route = $('#route-summary');
if (parseInt($route.attr('data-origin')) !== data.request.origin || parseInt($route.attr('data-destination')) !== data.request.destination) {
if ($route.attr('data-origin') !== String(data.request.origin) || $route.attr('data-destination') !== String(data.request.destination)) {
// loaded too late, information no longer needed
return;
}