diff --git a/src/c3nav/mapdata/utils/geometry.py b/src/c3nav/mapdata/utils/geometry.py index d79032a1..9e492503 100644 --- a/src/c3nav/mapdata/utils/geometry.py +++ b/src/c3nav/mapdata/utils/geometry.py @@ -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))) + diff --git a/src/c3nav/mapdata/utils/locations.py b/src/c3nav/mapdata/utils/locations.py index c3c7833c..2a4fc44d 100644 --- a/src/c3nav/mapdata/utils/locations.py +++ b/src/c3nav/mapdata/utils/locations.py @@ -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) diff --git a/src/c3nav/routing/forms.py b/src/c3nav/routing/forms.py index 1ef4fb6a..7d53ec48 100644 --- a/src/c3nav/routing/forms.py +++ b/src/c3nav/routing/forms.py @@ -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 diff --git a/src/c3nav/routing/router.py b/src/c3nav/routing/router.py index 3812f378..61c1966b 100644 --- a/src/c3nav/routing/router.py +++ b/src/c3nav/routing/router.py @@ -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): diff --git a/src/c3nav/site/static/site/js/c3nav.js b/src/c3nav/site/static/site/js/c3nav.js index 873c4b7c..52b6e77a 100644 --- a/src/c3nav/site/static/site/js/c3nav.js +++ b/src/c3nav/site/static/site/js/c3nav.js @@ -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; }