From 484f725aa6a6148741102bf2c0fe5d2916386107 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laura=20Kl=C3=BCnder?= Date: Fri, 20 Dec 2019 20:05:14 +0100 Subject: [PATCH] more performance optimization in altitudearea building and more comments --- src/c3nav/mapdata/models/geometry/level.py | 27 ++++++++++++++++------ src/c3nav/mapdata/utils/geometry.py | 7 ++++++ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/c3nav/mapdata/models/geometry/level.py b/src/c3nav/mapdata/models/geometry/level.py index 71104b6c..ca02b1c6 100644 --- a/src/c3nav/mapdata/models/geometry/level.py +++ b/src/c3nav/mapdata/models/geometry/level.py @@ -8,6 +8,7 @@ import numpy as np from django.core.validators import MinValueValidator from django.db import models from django.urls import reverse +from django.utils.functional import cached_property from django.utils.text import format_lazy from django.utils.translation import ugettext_lazy as _ from scipy.sparse.csgraph._shortest_path import dijkstra @@ -157,6 +158,16 @@ class Door(LevelGeometryMixin, AccessRestrictionMixin, models.Model): default_related_name = 'doors' +class ItemWithValue: + def __init__(self, obj, func): + self.obj = obj + self._func = func + + @cached_property + def value(self): + return self._func() + + class AltitudeArea(LevelGeometryMixin, models.Model): """ An altitude area @@ -529,15 +540,17 @@ class AltitudeArea(LevelGeometryMixin, models.Model): buffered = polygon.buffer(0.001) center = polygon.centroid - touches = tuple((area, buffered.intersection(area.orig_geometry).area) + touches = tuple(ItemWithValue(area, lambda: buffered.intersection(area.orig_geometry).area) for area in our_areas if area.orig_geometry_prep.intersects(buffered)) - if touches: - min_touches = sum((t[1] for t in touches), 0)/4 - area = max(touches, key=lambda item: (item[1] > min_touches, - item[0].altitude2 is not None, - item[0].altitude, - item[1]))[0] + if len(touches) == 1: + area = touches[0].obj + elif touches: + min_touches = sum((t.value for t in touches), 0)/4 + area = max(touches, key=lambda item: (item.value > min_touches, + item.obj.altitude2 is not None, + item.obj.altitude, + item.value)).obj else: area = min(our_areas, key=lambda a: a.orig_geometry.distance(center)-(0 if a.altitude2 is None else 0.6)) diff --git a/src/c3nav/mapdata/utils/geometry.py b/src/c3nav/mapdata/utils/geometry.py index 6311b68a..d4b6049c 100644 --- a/src/c3nav/mapdata/utils/geometry.py +++ b/src/c3nav/mapdata/utils/geometry.py @@ -361,16 +361,23 @@ def clean_cut_polygon(polygon: Polygon) -> Polygon: def cut_ring(ring: LinearRing) -> List[LinearRing]: + """ + Cuts a Linearring into multiple linearrings. Useful if the ring intersects with itself. + An 8-ring would be split into it's two circles for example. + """ rings = [] new_ring = [] # noinspection PyPropertyAccess for point in ring.coords: try: + # check if this point is already part of the ring index = new_ring.index(point) except ValueError: + # if not, append it new_ring.append(point) continue + # if yes, we got a loop, add it to the result and remove it from new_ring. if len(new_ring) > 2+index: rings.append(LinearRing(new_ring[index:]+[point])) new_ring = new_ring[:index+1]