From 1fcb92dd778cbfaceada57f55fcf8148a5772827 Mon Sep 17 00:00:00 2001 From: adeveloper-wq Date: Fri, 17 May 2024 13:42:52 +0200 Subject: [PATCH 1/3] Add debug hints for itself intersecting routes --- backend/backend/routing/views.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/backend/backend/routing/views.py b/backend/backend/routing/views.py index 3ed0532..a7863b8 100644 --- a/backend/backend/routing/views.py +++ b/backend/backend/routing/views.py @@ -1,7 +1,7 @@ import json import logging import time -from collections import namedtuple +from collections import namedtuple, Counter from typing import Iterable, List import os @@ -277,6 +277,16 @@ def post(self, request, *args, **kwargs): if usedRouting != "osm" and usedRouting != "drn": return JsonResponse({"error": "Unsupported value provided for the parameter 'routing'. Choose between 'osm' or 'drn'."}) + + if not route_linestring.simple: + print("Route is not simple!") + print(route_linestring.geojson) + unary_union = route_linestring.unary_union + coords_list = [] + for non_intersecting_geom in unary_union.coords[0]: + coords_list.append(non_intersecting_geom) + print("Intersection points:") + print([item for item, count in Counter(coords_list).items() if count > 1]) if matcher == "ml": unordered_lsas = get_matches(route_linestring, [ ProximityMatcher(search_radius_m=20), MLMatcher(usedRouting) ]) From 3c147b4a08abeb99d1aa8b281e7d58a50f0ee9f6 Mon Sep 17 00:00:00 2001 From: Philipp Matthes Date: Mon, 15 Jul 2024 13:44:54 +0200 Subject: [PATCH 2/3] Match multiple parts of the route individually in case of self-intersection --- backend/backend/routing/matching/__init__.py | 2 +- backend/backend/routing/views.py | 48 ++++++++++++-------- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/backend/backend/routing/matching/__init__.py b/backend/backend/routing/matching/__init__.py index 83e7e13..b690f88 100644 --- a/backend/backend/routing/matching/__init__.py +++ b/backend/backend/routing/matching/__init__.py @@ -39,7 +39,7 @@ def matches(self, lsas: QuerySet, route: LineString) -> Tuple[QuerySet, LineStri return lsas.filter(pk__in=pks_to_include), route -def get_matches(route: LineString, matchers: List[RouteMatcher]) -> Iterable[LSA]: +def get_matches(route: LineString, matchers: List[RouteMatcher]) -> QuerySet[LSA]: """ Return all LSA's that match the route. """ diff --git a/backend/backend/routing/views.py b/backend/backend/routing/views.py index a7863b8..99c1734 100644 --- a/backend/backend/routing/views.py +++ b/backend/backend/routing/views.py @@ -1,16 +1,16 @@ import json import logging +import os import time -from collections import namedtuple, Counter +from collections import Counter, namedtuple from typing import Iterable, List -import os import pyproj from django.conf import settings from django.contrib.gis.geos import LineString, Point from django.contrib.gis.measure import D from django.core.exceptions import ValidationError -from django.http import JsonResponse, HttpResponseServerError +from django.http import HttpResponseServerError, JsonResponse from django.http.response import HttpResponse from django.utils.decorators import method_decorator from django.views.decorators.csrf import csrf_exempt @@ -277,23 +277,33 @@ def post(self, request, *args, **kwargs): if usedRouting != "osm" and usedRouting != "drn": return JsonResponse({"error": "Unsupported value provided for the parameter 'routing'. Choose between 'osm' or 'drn'."}) - - if not route_linestring.simple: - print("Route is not simple!") - print(route_linestring.geojson) - unary_union = route_linestring.unary_union - coords_list = [] - for non_intersecting_geom in unary_union.coords[0]: - coords_list.append(non_intersecting_geom) - print("Intersection points:") - print([item for item, count in Counter(coords_list).items() if count > 1]) - - if matcher == "ml": - unordered_lsas = get_matches(route_linestring, [ ProximityMatcher(search_radius_m=20), MLMatcher(usedRouting) ]) - elif matcher == "legacy": - unordered_lsas = get_matches(route_linestring, [ TopologicHypermodelMatcher.from_config_file(f'config/topologic.hypermodel.{usedRouting}.updated.json') ]) + + if route_linestring.simple: + route_parts = [route_linestring] else: - return JsonResponse({"error": "Unsupported value provided for the parameter 'matcher'. Choose between 'ml' or 'legacy'."}) + # If the route crosses itself, we split it into parts and match each part separately. + # Each part is buffered a bit to make sure the parts keep crossing the intersection fully. + unary_union = route_linestring.unary_union # multilinestring + route_parts = [] + buffer = 100 # distance in meter + buffer_wgs84 = buffer / 40000000.0 * 360.0 # wgs84 + for part in unary_union: + buffered = route_linestring.intersection(part.buffer(buffer_wgs84)) + route_parts.append(buffered) + + unordered_lsas = None # or queryset + for route_part in route_parts: # one part if the route does not cross itself, otherwise multiple buffered parts + if matcher == "ml": + matches = get_matches(route_part, [ ProximityMatcher(search_radius_m=20), MLMatcher(usedRouting) ]) + elif matcher == "legacy": + matches = get_matches(route_part, [ TopologicHypermodelMatcher.from_config_file(f'config/topologic.hypermodel.{usedRouting}.updated.json') ]) + else: + return JsonResponse({"error": "Unsupported value provided for the parameter 'matcher'. Choose between 'ml' or 'legacy'."}) + if unordered_lsas is None: + unordered_lsas = matches + else: + # Remove duplicates from the matches. This may happen when the route crosses itself. + unordered_lsas = unordered_lsas.union(matches) # Snap the LSA positions to the route as marked waypoints lsa_snaps = snap_lsas(unordered_lsas, route_linestring) From 6a9e6c34c2bf4d4ae4a4e6dcbbf58f5b358555ed Mon Sep 17 00:00:00 2001 From: Philipp Matthes Date: Mon, 15 Jul 2024 13:45:50 +0200 Subject: [PATCH 3/3] Remove counter and os import --- backend/backend/routing/views.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/backend/routing/views.py b/backend/backend/routing/views.py index 99c1734..66be554 100644 --- a/backend/backend/routing/views.py +++ b/backend/backend/routing/views.py @@ -1,8 +1,7 @@ import json import logging -import os import time -from collections import Counter, namedtuple +from collections import namedtuple from typing import Iterable, List import pyproj