route from/to custom locations
This commit is contained in:
parent
f5ee24495e
commit
b92c871bc2
5 changed files with 39 additions and 17 deletions
|
@ -69,6 +69,8 @@ def assert_multilinestring(geometry: Union[LineString, MultiLineString, Geometry
|
||||||
|
|
||||||
|
|
||||||
def good_representative_point(geometry):
|
def good_representative_point(geometry):
|
||||||
|
if isinstance(geometry, Point):
|
||||||
|
return geometry
|
||||||
c = geometry.centroid
|
c = geometry.centroid
|
||||||
x1, y1, x2, y2 = geometry.bounds
|
x1, y1, x2, y2 = geometry.bounds
|
||||||
lines = (tuple(assert_multilinestring(LineString(((x1, c.y), (x2, c.y))).intersection(geometry))) +
|
lines = (tuple(assert_multilinestring(LineString(((x1, c.y), (x2, c.y))).intersection(geometry))) +
|
||||||
|
|
|
@ -227,6 +227,8 @@ def get_custom_location_for_request(slug: str, request):
|
||||||
|
|
||||||
class CustomLocation:
|
class CustomLocation:
|
||||||
can_search = True
|
can_search = True
|
||||||
|
can_describe = True
|
||||||
|
access_restriction_id = None
|
||||||
|
|
||||||
def __init__(self, level, x, y):
|
def __init__(self, level, x, y):
|
||||||
x = round(x, 2)
|
x = round(x, 2)
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.utils.translation import ugettext_lazy
|
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):
|
class RouteForm(forms.Form):
|
||||||
origin = forms.IntegerField(min_value=1)
|
origin = forms.CharField()
|
||||||
destination = forms.IntegerField(min_value=1)
|
destination = forms.CharField()
|
||||||
|
|
||||||
def __init__(self, *args, request=None, **kwargs):
|
def __init__(self, *args, request=None, **kwargs):
|
||||||
self.request = request
|
self.request = request
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
def clean_origin(self):
|
def clean_origin(self):
|
||||||
try:
|
location = get_location_by_id_for_request(self.cleaned_data['origin'], self.request)
|
||||||
return locations_for_request(self.request)[self.cleaned_data['origin']]
|
if location is None:
|
||||||
except KeyError:
|
|
||||||
raise forms.ValidationError(ugettext_lazy('Unknown origin.'))
|
raise forms.ValidationError(ugettext_lazy('Unknown origin.'))
|
||||||
|
return location
|
||||||
|
|
||||||
def clean_destination(self):
|
def clean_destination(self):
|
||||||
try:
|
location = get_location_by_id_for_request(self.cleaned_data['destination'], self.request)
|
||||||
return locations_for_request(self.request)[self.cleaned_data['destination']]
|
if location is None:
|
||||||
except KeyError:
|
|
||||||
raise forms.ValidationError(ugettext_lazy('Unknown destination.'))
|
raise forms.ValidationError(ugettext_lazy('Unknown destination.'))
|
||||||
|
return location
|
||||||
|
|
|
@ -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 import AltitudeArea, Area, GraphEdge, Level, LocationGroup, Space, WayType
|
||||||
from c3nav.mapdata.models.geometry.space import POI
|
from c3nav.mapdata.models.geometry.space import POI
|
||||||
from c3nav.mapdata.utils.geometry import assert_multipolygon, good_representative_point
|
from c3nav.mapdata.utils.geometry import assert_multipolygon, good_representative_point
|
||||||
|
from c3nav.mapdata.utils.locations import CustomLocation
|
||||||
from c3nav.routing.route import Route
|
from c3nav.routing.route import Route
|
||||||
|
|
||||||
|
|
||||||
|
@ -122,7 +123,7 @@ class Router:
|
||||||
# todo: check waytypes here
|
# todo: check waytypes here
|
||||||
for node in space_nodes:
|
for node in space_nodes:
|
||||||
line = LineString([(node.x, node.y), (fallback_node.x, fallback_node.y)])
|
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] = (
|
area.fallback_nodes[node.i] = (
|
||||||
fallback_node,
|
fallback_node,
|
||||||
RouterEdge(fallback_node, node, 0)
|
RouterEdge(fallback_node, node, 0)
|
||||||
|
@ -139,10 +140,9 @@ class Router:
|
||||||
groups.setdefault(group.pk, {}).setdefault('pois', set()).add(poi.pk)
|
groups.setdefault(group.pk, {}).setdefault('pois', set()).add(poi.pk)
|
||||||
poi._prefetched_objects_cache = {}
|
poi._prefetched_objects_cache = {}
|
||||||
|
|
||||||
poi = RouterPOI(poi)
|
poi = RouterPoint(poi)
|
||||||
altitudearea = space.altitudearea_for_point(poi.geometry)
|
altitudearea = space.altitudearea_for_point(poi.geometry)
|
||||||
poi_nodes = altitudearea.nodes_for_point(poi.geometry, all_nodes=nodes)
|
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 = set(i for i in poi_nodes.keys())
|
||||||
poi.nodes_addition = poi_nodes
|
poi.nodes_addition = poi_nodes
|
||||||
pois[poi.pk] = poi
|
pois[poi.pk] = poi
|
||||||
|
@ -212,11 +212,29 @@ class Router:
|
||||||
(self.spaces[pk] for pk in group.get('spaces', ())),
|
(self.spaces[pk] for pk in group.get('spaces', ())),
|
||||||
(self.areas[pk] for pk in group.get('areas', ()))
|
(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
|
# todo: route from/to custom location
|
||||||
return RouterLocation(tuple(location for location in locations
|
return RouterLocation(tuple(location for location in locations
|
||||||
if location is not None and (location.access_restriction_id is None or
|
if location is not None and (location.access_restriction_id is None or
|
||||||
location.access_restriction_id in permissions)))
|
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()):
|
def get_route(self, origin, destination, permissions=frozenset()):
|
||||||
# get possible origins and destinations
|
# get possible origins and destinations
|
||||||
origins = self.get_locations(origin, permissions=permissions)
|
origins = self.get_locations(origin, permissions=permissions)
|
||||||
|
@ -289,14 +307,14 @@ class RouterSpace(BaseRouterProxy):
|
||||||
for area in self.altitudeareas:
|
for area in self.altitudeareas:
|
||||||
if area.geometry_prep.intersects(point):
|
if area.geometry_prep.intersects(point):
|
||||||
return area
|
return area
|
||||||
return self.altitudareas[0]
|
return min(self.altitudeareas, key=lambda area: area.geometry.distance(point))
|
||||||
|
|
||||||
|
|
||||||
class RouterArea(BaseRouterProxy):
|
class RouterArea(BaseRouterProxy):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class RouterPOI(BaseRouterProxy):
|
class RouterPoint(BaseRouterProxy):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@ -331,7 +349,7 @@ class RouterAltitudeArea:
|
||||||
for node in self.nodes:
|
for node in self.nodes:
|
||||||
node = all_nodes[node]
|
node = all_nodes[node]
|
||||||
line = LineString([(node.x, node.y), (point.x, point.y)])
|
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
|
nodes[node.i] = None
|
||||||
if not nodes:
|
if not nodes:
|
||||||
nearest_node = min(tuple(all_nodes[node] for node in self.nodes),
|
nearest_node = min(tuple(all_nodes[node] for node in self.nodes),
|
||||||
|
@ -394,7 +412,7 @@ class RouterWayType:
|
||||||
|
|
||||||
class RouterLocation:
|
class RouterLocation:
|
||||||
def __init__(self, locations=()):
|
def __init__(self, locations=()):
|
||||||
self.locations = tuple(location for location in locations if locations)
|
self.locations = locations
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def nodes(self):
|
def nodes(self):
|
||||||
|
|
|
@ -218,7 +218,7 @@ c3nav = {
|
||||||
},
|
},
|
||||||
_route_loaded: function(data, nofly) {
|
_route_loaded: function(data, nofly) {
|
||||||
var $route = $('#route-summary');
|
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
|
// loaded too late, information no longer needed
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue