From c9661e4edbfdd09eddcc0bdf26c610db09d080f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laura=20Kl=C3=BCnder?= Date: Sun, 7 May 2017 12:06:13 +0200 Subject: [PATCH] rename Level to Section --- src/c3nav/api/urls.py | 4 +- src/c3nav/editor/forms.py | 25 ++------- src/c3nav/editor/urls.py | 2 +- src/c3nav/editor/views.py | 44 +++++++--------- src/c3nav/mapdata/api.py | 41 ++++----------- .../migrations/0059_auto_20170507_0937.py | 19 +++++++ .../migrations/0060_auto_20170507_0952.py | 40 +++++++++++++++ .../migrations/0061_auto_20170507_0953.py | 51 +++++++++++++++++++ src/c3nav/mapdata/models/__init__.py | 2 +- src/c3nav/mapdata/models/base.py | 3 +- src/c3nav/mapdata/models/geometry/__init__.py | 3 -- src/c3nav/mapdata/models/geometry/base.py | 3 +- .../models/geometry/{level.py => section.py} | 19 +++---- src/c3nav/mapdata/models/geometry/space.py | 4 +- src/c3nav/mapdata/models/locations.py | 22 ++++---- .../mapdata/models/{level.py => section.py} | 43 ++++++++-------- src/c3nav/mapdata/render/__init__.py | 4 +- src/c3nav/mapdata/search.py | 12 ++--- src/c3nav/mapdata/serializers/main.py | 7 +-- src/c3nav/mapdata/utils/cache.py | 8 +-- src/c3nav/routing/graph.py | 6 +-- src/c3nav/site/views.py | 12 ++--- 22 files changed, 217 insertions(+), 157 deletions(-) create mode 100644 src/c3nav/mapdata/migrations/0059_auto_20170507_0937.py create mode 100644 src/c3nav/mapdata/migrations/0060_auto_20170507_0952.py create mode 100644 src/c3nav/mapdata/migrations/0061_auto_20170507_0953.py rename src/c3nav/mapdata/models/geometry/{level.py => section.py} (83%) rename src/c3nav/mapdata/models/{level.py => section.py} (84%) diff --git a/src/c3nav/api/urls.py b/src/c3nav/api/urls.py index 60abb2b2..749240d0 100644 --- a/src/c3nav/api/urls.py +++ b/src/c3nav/api/urls.py @@ -7,10 +7,10 @@ from rest_framework.generics import GenericAPIView from rest_framework.response import Response from rest_framework.routers import SimpleRouter -from c3nav.mapdata.api import GeometryTypeViewSet, GeometryViewSet, LevelViewSet, LocationViewSet, SourceViewSet +from c3nav.mapdata.api import GeometryTypeViewSet, GeometryViewSet, LocationViewSet, SectionViewSet, SourceViewSet router = SimpleRouter() -router.register(r'levels', LevelViewSet) +router.register(r'sections', SectionViewSet) router.register(r'sources', SourceViewSet) router.register(r'geometrytypes', GeometryTypeViewSet, base_name='geometrytype') diff --git a/src/c3nav/editor/forms.py b/src/c3nav/editor/forms.py index bf4343b4..0e90d2ec 100644 --- a/src/c3nav/editor/forms.py +++ b/src/c3nav/editor/forms.py @@ -22,22 +22,9 @@ class MapitemFormMixin(ModelForm): if creating: self.fields['name'].initial = hex(int(time.time()*1000000))[2:] - if 'level' in self.fields: - # hide level widget and set field_name - self.fields['level'].widget = HiddenInput() - self.fields['level'].to_field_name = 'name' - if not creating: - self.initial['level'] = self.instance.level.name - - if 'crop_to_level' in self.fields: - # set field_name - self.fields['crop_to_level'].to_field_name = 'name' - if not creating and self.instance.crop_to_level is not None: - self.initial['crop_to_level'] = self.instance.crop_to_level.name - - if 'levels' in self.fields: - # set field_name - self.fields['levels'].to_field_name = 'name' + if 'section' in self.fields: + # hide section widget + self.fields['section'].widget = HiddenInput() if 'groups' in self.fields: # set field_name @@ -66,12 +53,6 @@ class MapitemFormMixin(ModelForm): initial=titles[language].strip(), max_length=50) self.titles = titles - def clean_levels(self): - levels = self.cleaned_data.get('levels') - if len(levels) < 2: - raise ValidationError(_('Please select at least two levels.')) - return levels - def clean(self): if 'geometry' in self.fields: if not self.cleaned_data.get('geometry'): diff --git a/src/c3nav/editor/urls.py b/src/c3nav/editor/urls.py index fdea1009..998cecd7 100644 --- a/src/c3nav/editor/urls.py +++ b/src/c3nav/editor/urls.py @@ -7,7 +7,7 @@ urlpatterns = [ url(r'^$', TemplateView.as_view(template_name='editor/map.html'), name='editor.index'), url(r'^mapitemtypes/(?P[^/]+)/$', list_mapitemtypes, name='editor.mapitemtypes'), url(r'^mapitems/(?P[^/]+)/list/$', list_mapitems, name='editor.mapitems'), - url(r'^mapitems/(?P[^/]+)/list/(?P[^/]+)/$', list_mapitems, name='editor.mapitems.level'), + url(r'^mapitems/(?P[^/]+)/list/(?P[0-9]+)/$', list_mapitems, name='editor.mapitems.level'), url(r'^mapitems/(?P[^/]+)/add/$', edit_mapitem, name='editor.mapitems.add'), url(r'^mapitems/(?P[^/]+)/edit/(?P[^/]+)/$', edit_mapitem, name='editor.mapitems.edit'), ] diff --git a/src/c3nav/editor/views.py b/src/c3nav/editor/views.py index aabaa294..8ea86704 100644 --- a/src/c3nav/editor/views.py +++ b/src/c3nav/editor/views.py @@ -4,54 +4,49 @@ from django.http.response import Http404 from django.shortcuts import get_object_or_404, redirect, render from c3nav.access.apply import can_access, filter_queryset_by_access -from c3nav.mapdata.models import AreaLocation, Level +from c3nav.mapdata.models import AreaLocation, Section from c3nav.mapdata.models.base import FEATURE_TYPES -def list_mapitemtypes(request, level): - level = get_object_or_404() +def list_mapitemtypes(request, section): + section = get_object_or_404(Section, pk=section) def get_item_count(mapitemtype): - if hasattr(mapitemtype, 'level'): - return filter_queryset_by_access(request, mapitemtype.objects.filter(level__name=level)).count() - - if hasattr(mapitemtype, 'levels'): - return filter_queryset_by_access(request, mapitemtype.objects.filter(levels__name=level)).count() + if hasattr(mapitemtype, 'section'): + return filter_queryset_by_access(request, mapitemtype.objects.filter(section=section)).count() return 0 return render(request, 'editor/mapitemtypes.html', { - 'level': level, + 'section': section, 'mapitemtypes': [ { 'name': name, 'title': mapitemtype._meta.verbose_name_plural, - 'has_level': hasattr(mapitemtype, 'level') or hasattr(mapitemtype, 'levels'), + 'has_section': hasattr(mapitemtype, 'section'), 'count': get_item_count(mapitemtype), } for name, mapitemtype in FEATURE_TYPES.items() ], }) -def list_mapitems(request, mapitem_type, level=None): +def list_mapitems(request, mapitem_type, section=None): mapitemtype = FEATURE_TYPES.get(mapitem_type) if mapitemtype is None: raise Http404('Unknown mapitemtype.') - has_level = hasattr(mapitemtype, 'level') or hasattr(mapitemtype, 'levels') - if has_level and level is None: - raise Http404('Missing level.') - elif not has_level and level is not None: + has_section = hasattr(mapitemtype, 'section') + if has_section and section is None: + raise Http404('Missing section.') + elif not has_section and section is not None: return redirect('editor.mapitems', mapitem_type=mapitem_type) queryset = mapitemtype.objects.all().order_by('name') - if level is not None: - level = get_object_or_404(Level, level) - if hasattr(mapitemtype, 'level'): - queryset = queryset.filter(level=level) - elif hasattr(mapitemtype, 'levels'): - queryset = queryset.filter(levels=level) + if section is not None: + section = get_object_or_404(Section, section) + if hasattr(mapitemtype, 'section'): + queryset = queryset.filter(section=section) queryset = filter_queryset_by_access(request, queryset) @@ -61,12 +56,9 @@ def list_mapitems(request, mapitem_type, level=None): return render(request, 'editor/mapitems.html', { 'mapitem_type': mapitem_type, 'title': mapitemtype._meta.verbose_name_plural, - 'has_level': level is not None, - 'has_elevator': hasattr(mapitemtype, 'elevator'), - 'has_levels': hasattr(mapitemtype, 'levels'), + 'has_section': section is not None, 'has_altitude': hasattr(mapitemtype, 'altitude'), - 'has_intermediate': hasattr(mapitemtype, 'intermediate'), - 'level': level.id, + 'section': section.id, 'items': queryset, }) diff --git a/src/c3nav/mapdata/api.py b/src/c3nav/mapdata/api.py index f9f2f0c0..5f110614 100644 --- a/src/c3nav/mapdata/api.py +++ b/src/c3nav/mapdata/api.py @@ -4,18 +4,18 @@ import mimetypes from collections import OrderedDict from django.http import Http404, HttpResponse, HttpResponseNotModified -from django.shortcuts import get_object_or_404 from rest_framework.decorators import detail_route, list_route from rest_framework.response import Response from rest_framework.viewsets import ReadOnlyModelViewSet, ViewSet from c3nav.access.apply import filter_arealocations_by_access, filter_queryset_by_access from c3nav.mapdata.lastupdate import get_last_mapdata_update -from c3nav.mapdata.models import AreaLocation, Level, LocationGroup, Source -from c3nav.mapdata.models.geometry.space import Stair +from c3nav.mapdata.models import AreaLocation, LocationGroup, Source from c3nav.mapdata.models.geometry.base import GEOMETRY_FEATURE_TYPES +from c3nav.mapdata.models.geometry.space import Stair +from c3nav.mapdata.models.section import Section from c3nav.mapdata.search import get_location -from c3nav.mapdata.serializers.main import LevelSerializer, SourceSerializer +from c3nav.mapdata.serializers.main import SectionSerializer, SourceSerializer from c3nav.mapdata.utils.cache import CachedReadOnlyViewSetMixin, cache_mapdata_api_response, get_bssid_areas_cached @@ -37,7 +37,6 @@ class GeometryTypeViewSet(ViewSet): class GeometryViewSet(ViewSet): """ List all geometries. - You can filter by adding a level GET parameter. """ def list(self, request): types = set(request.GET.getlist('type')) @@ -47,45 +46,25 @@ class GeometryViewSet(ViewSet): else: types = [t for t in valid_types if t in types] - level = None - if 'level' in request.GET: - level = get_object_or_404(Level, id=request.GET['level']) - cache_key = '__'.join(( ','.join([str(i) for i in types]), - str(level.id) if level is not None else '', )) - return self._list(request, types=types, level=level, add_cache_key=cache_key) + return self._list(request, types=types, add_cache_key=cache_key) @staticmethod def compare_by_location_type(x: AreaLocation, y: AreaLocation): return AreaLocation.LOCATION_TYPES.index(x.location_type) - AreaLocation.LOCATION_TYPES.index(y.location_type) @cache_mapdata_api_response() - def _list(self, request, types, level): + def _list(self, request, types): results = [] for t in types: mapitemtype = GEOMETRY_FEATURE_TYPES[t] queryset = mapitemtype.objects.all() - if level: - if hasattr(mapitemtype, 'level'): - queryset = queryset.filter(level=level) - elif hasattr(mapitemtype, 'levels'): - queryset = queryset.filter(levels=level) - else: - queryset = queryset.none() queryset = filter_queryset_by_access(request, queryset) queryset = queryset.order_by('id') - for field_name in ('level', 'crop_to_level', 'elevator'): - if hasattr(mapitemtype, field_name): - queryset = queryset.select_related(field_name) - - for field_name in ('levels', ): - if hasattr(mapitemtype, field_name): - queryset.prefetch_related(field_name) - if issubclass(mapitemtype, AreaLocation): queryset = sorted(queryset, key=AreaLocation.get_sort_key) @@ -97,12 +76,12 @@ class GeometryViewSet(ViewSet): return Response(results) -class LevelViewSet(CachedReadOnlyViewSetMixin, ReadOnlyModelViewSet): +class SectionViewSet(CachedReadOnlyViewSetMixin, ReadOnlyModelViewSet): """ - List and retrieve levels. + List and retrieve sections. """ - queryset = Level.objects.all() - serializer_class = LevelSerializer + queryset = Section.objects.all() + serializer_class = SectionSerializer lookup_field = 'id' diff --git a/src/c3nav/mapdata/migrations/0059_auto_20170507_0937.py b/src/c3nav/mapdata/migrations/0059_auto_20170507_0937.py new file mode 100644 index 00000000..80e70272 --- /dev/null +++ b/src/c3nav/mapdata/migrations/0059_auto_20170507_0937.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-05-07 09:37 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('mapdata', '0058_auto_20170506_1549'), + ] + + operations = [ + migrations.RenameModel( + old_name='Level', + new_name='Section', + ), + ] diff --git a/src/c3nav/mapdata/migrations/0060_auto_20170507_0952.py b/src/c3nav/mapdata/migrations/0060_auto_20170507_0952.py new file mode 100644 index 00000000..e9511514 --- /dev/null +++ b/src/c3nav/mapdata/migrations/0060_auto_20170507_0952.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-05-07 09:52 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('mapdata', '0059_auto_20170507_0937'), + ] + + operations = [ + migrations.RenameField( + model_name='arealocation', + old_name='level', + new_name='section', + ), + migrations.RenameField( + model_name='building', + old_name='level', + new_name='section', + ), + migrations.RenameField( + model_name='door', + old_name='level', + new_name='section', + ), + migrations.RenameField( + model_name='hole', + old_name='level', + new_name='section', + ), + migrations.RenameField( + model_name='space', + old_name='level', + new_name='section', + ), + ] diff --git a/src/c3nav/mapdata/migrations/0061_auto_20170507_0953.py b/src/c3nav/mapdata/migrations/0061_auto_20170507_0953.py new file mode 100644 index 00000000..77af699f --- /dev/null +++ b/src/c3nav/mapdata/migrations/0061_auto_20170507_0953.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-05-07 09:53 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('mapdata', '0060_auto_20170507_0952'), + ] + + operations = [ + migrations.AlterField( + model_name='arealocation', + name='section', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='arealocations', to='mapdata.Section', verbose_name='section'), + ), + migrations.AlterField( + model_name='building', + name='section', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='buildings', to='mapdata.Section', verbose_name='section'), + ), + migrations.AlterField( + model_name='door', + name='section', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='doors', to='mapdata.Section', verbose_name='section'), + ), + migrations.AlterField( + model_name='hole', + name='section', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='holes', to='mapdata.Section', verbose_name='section'), + ), + migrations.AlterField( + model_name='section', + name='altitude', + field=models.DecimalField(decimal_places=2, max_digits=6, unique=True, verbose_name='section altitude'), + ), + migrations.AlterField( + model_name='section', + name='name', + field=models.SlugField(unique=True, verbose_name='section name'), + ), + migrations.AlterField( + model_name='space', + name='section', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='areas', to='mapdata.Section', verbose_name='section'), + ), + ] diff --git a/src/c3nav/mapdata/models/__init__.py b/src/c3nav/mapdata/models/__init__.py index 071ea822..7c51e961 100644 --- a/src/c3nav/mapdata/models/__init__.py +++ b/src/c3nav/mapdata/models/__init__.py @@ -1,3 +1,3 @@ -from .level import Level # noqa +from .section import Section # noqa from .source import Source # noqa from .locations import AreaLocation, LocationGroup # noqa diff --git a/src/c3nav/mapdata/models/base.py b/src/c3nav/mapdata/models/base.py index 0ebc1a6a..4896ac01 100644 --- a/src/c3nav/mapdata/models/base.py +++ b/src/c3nav/mapdata/models/base.py @@ -1,4 +1,5 @@ from collections import OrderedDict + from django.db import models from django.db.models.base import ModelBase from django.utils.translation import get_language @@ -38,5 +39,3 @@ class Feature(models.Model, metaclass=FeatureBase): class Meta: abstract = True - - diff --git a/src/c3nav/mapdata/models/geometry/__init__.py b/src/c3nav/mapdata/models/geometry/__init__.py index b28b04f6..e69de29b 100644 --- a/src/c3nav/mapdata/models/geometry/__init__.py +++ b/src/c3nav/mapdata/models/geometry/__init__.py @@ -1,3 +0,0 @@ - - - diff --git a/src/c3nav/mapdata/models/geometry/base.py b/src/c3nav/mapdata/models/geometry/base.py index e858dc52..f33545f9 100644 --- a/src/c3nav/mapdata/models/geometry/base.py +++ b/src/c3nav/mapdata/models/geometry/base.py @@ -1,5 +1,6 @@ from collections import OrderedDict -from shapely.geometry import mapping, Point + +from shapely.geometry import Point, mapping from c3nav.mapdata.fields import GeometryField from c3nav.mapdata.models.base import Feature, FeatureBase diff --git a/src/c3nav/mapdata/models/geometry/level.py b/src/c3nav/mapdata/models/geometry/section.py similarity index 83% rename from src/c3nav/mapdata/models/geometry/level.py rename to src/c3nav/mapdata/models/geometry/section.py index 568380c3..3c3a3ace 100644 --- a/src/c3nav/mapdata/models/geometry/level.py +++ b/src/c3nav/mapdata/models/geometry/section.py @@ -1,4 +1,5 @@ from collections import OrderedDict + from django.db import models from django.utils.translation import ugettext_lazy as _ @@ -7,7 +8,7 @@ from c3nav.mapdata.models.geometry.base import GeometryFeature, GeometryFeatureB LEVEL_FEATURE_TYPES = OrderedDict() -class LevelFeatureBase(GeometryFeatureBase): +class SectionFeatureBase(GeometryFeatureBase): def __new__(mcs, name, bases, attrs): cls = super().__new__(mcs, name, bases, attrs) if not cls._meta.abstract: @@ -15,22 +16,22 @@ class LevelFeatureBase(GeometryFeatureBase): return cls -class LevelFeature(GeometryFeature, metaclass=LevelFeatureBase): +class SectionFeature(GeometryFeature, metaclass=SectionFeatureBase): """ - a map feature that has a geometry and belongs to a level + a map feature that has a geometry and belongs to a section """ - level = models.ForeignKey('mapdata.Level', on_delete=models.CASCADE, verbose_name=_('level')) + section = models.ForeignKey('mapdata.Section', on_delete=models.CASCADE, verbose_name=_('section')) class Meta: abstract = True def get_geojson_properties(self): result = super().get_geojson_properties() - result['level'] = self.level.id + result['section'] = self.section.id return result -class Building(LevelFeature): +class Building(SectionFeature): """ The outline of a building on a specific level """ @@ -42,7 +43,7 @@ class Building(LevelFeature): default_related_name = 'buildings' -class Space(LevelFeature): +class Space(SectionFeature): """ An accessible space. Shouldn't overlap. """ @@ -77,7 +78,7 @@ class Space(LevelFeature): return result -class Door(LevelFeature): +class Door(SectionFeature): """ A connection between two rooms """ @@ -89,7 +90,7 @@ class Door(LevelFeature): default_related_name = 'doors' -class Hole(LevelFeature): +class Hole(SectionFeature): """ A hole in the ground of a room, e.g. for stairs. """ diff --git a/src/c3nav/mapdata/models/geometry/space.py b/src/c3nav/mapdata/models/geometry/space.py index 508433f3..8408294c 100644 --- a/src/c3nav/mapdata/models/geometry/space.py +++ b/src/c3nav/mapdata/models/geometry/space.py @@ -1,12 +1,12 @@ from collections import OrderedDict + from django.db import models from django.utils.translation import ugettext_lazy as _ -from shapely.geometry import JOIN_STYLE, CAP_STYLE, mapping +from shapely.geometry import CAP_STYLE, JOIN_STYLE, mapping from c3nav.mapdata.models.geometry.base import GeometryFeature, GeometryFeatureBase from c3nav.mapdata.utils.json import format_geojson - SPACE_FEATURE_TYPES = OrderedDict() diff --git a/src/c3nav/mapdata/models/locations.py b/src/c3nav/mapdata/models/locations.py index 0038ee2e..8851b796 100644 --- a/src/c3nav/mapdata/models/locations.py +++ b/src/c3nav/mapdata/models/locations.py @@ -9,9 +9,9 @@ from django.utils.translation import ungettext_lazy from c3nav.mapdata.fields import JSONField, validate_bssid_lines from c3nav.mapdata.lastupdate import get_last_mapdata_update -from c3nav.mapdata.models import Level from c3nav.mapdata.models.base import Feature -from c3nav.mapdata.models.geometry.level import LevelFeature +from c3nav.mapdata.models.geometry.section import SectionFeature +from c3nav.mapdata.models.section import Section class Location: @@ -85,7 +85,7 @@ class LocationGroup(LocationModelMixin, Feature): level_ids.add(area.id) in_levels.append(area) - in_levels = sorted(in_levels, key=lambda area: area.level.altitude) + in_levels = sorted(in_levels, key=lambda area: area.section.altitude) return in_levels @property @@ -102,7 +102,7 @@ class LocationGroup(LocationModelMixin, Feature): return result -class AreaLocation(LocationModelMixin, LevelFeature): +class AreaLocation(LocationModelMixin, SectionFeature): LOCATION_TYPES = ( ('level', _('Level')), ('area', _('General Area')), @@ -162,7 +162,7 @@ class AreaLocation(LocationModelMixin, LevelFeature): in_areas = [] area_location_i = self.get_sort_key(self) for location_type in reversed(self.LOCATION_TYPES_ORDER[:area_location_i]): - for arealocation in AreaLocation.objects.filter(location_type=location_type, level=self.level): + for arealocation in AreaLocation.objects.filter(location_type=location_type, section=self.section): intersection_area = arealocation.geometry.intersection(self.geometry).area if intersection_area and intersection_area / my_area > 0.99: in_areas.append(arealocation) @@ -196,15 +196,15 @@ class AreaLocation(LocationModelMixin, LevelFeature): class PointLocation(Location): - def __init__(self, level: Level, x: int, y: int, request): - self.level = level + def __init__(self, section: Section, x: int, y: int, request): + self.section = section self.x = x self.y = y self.request = request @cached_property def location_id(self): - return 'c:%s:%d:%d' % (self.level.name, self.x*100, self.y*100) + return 'c:%d:%d:%d' % (self.section.id, self.x * 100, self.y * 100) @cached_property def xy(self): @@ -214,7 +214,7 @@ class PointLocation(Location): def description(self): from c3nav.routing.graph import Graph graph = Graph.load() - point = graph.get_nearest_point(self.level, self.x, self.y) + point = graph.get_nearest_point(self.section, self.x, self.y) if point is None or (':nonpublic' in point.arealocations and not self.request.c3nav_full_access and not len(set(self.request.c3nav_access_list) & set(point.arealocations))): @@ -239,14 +239,14 @@ class PointLocation(Location): @property def subtitle(self) -> str: add_subtitle = self.description[1] - subtitle = '%s:%d:%d' % (self.level.name, self.x*100, self.y*100) + subtitle = '%s:%d:%d' % (self.section.name, self.x * 100, self.y * 100) if add_subtitle: subtitle += ' - '+add_subtitle return subtitle def to_location_json(self): result = super().to_location_json() - result['level'] = self.level.name + result['section'] = self.section.id result['x'] = self.x result['y'] = self.y return result diff --git a/src/c3nav/mapdata/models/level.py b/src/c3nav/mapdata/models/section.py similarity index 84% rename from src/c3nav/mapdata/models/level.py rename to src/c3nav/mapdata/models/section.py index 94526f91..3688e910 100644 --- a/src/c3nav/mapdata/models/level.py +++ b/src/c3nav/mapdata/models/section.py @@ -8,18 +8,17 @@ from c3nav.mapdata.models.base import Feature from c3nav.mapdata.utils.geometry import assert_multilinestring, assert_multipolygon -class Level(Feature): +class Section(Feature): """ - A map level (-1, 0, 1, 2…) + A map section like a level """ - name = models.SlugField(_('level name'), unique=True, max_length=50, - help_text=_('Usually just an integer (e.g. -1, 0, 1, 2)')) - altitude = models.DecimalField(_('level altitude'), null=False, unique=True, max_digits=6, decimal_places=2) + name = models.SlugField(_('section name'), unique=True, max_length=50) + altitude = models.DecimalField(_('section altitude'), null=False, unique=True, max_digits=6, decimal_places=2) class Meta: - verbose_name = _('Level') - verbose_name_plural = _('Levels') - default_related_name = 'levels' + verbose_name = _('Section') + verbose_name_plural = _('Sections') + default_related_name = 'sections' ordering = ['altitude'] def __init__(self, *args, **kwargs): @@ -27,35 +26,35 @@ class Level(Feature): @cached_property def public_geometries(self): - return LevelGeometries.by_level(self, only_public=True) + return SectionGeometries.by_section(self, only_public=True) @cached_property def geometries(self): - return LevelGeometries.by_level(self, only_public=False) + return SectionGeometries.by_section(self, only_public=False) def lower(self): - return Level.objects.filter(altitude__lt=self.altitude).order_by('altitude') + return Section.objects.filter(altitude__lt=self.altitude).order_by('altitude') def higher(self): - return Level.objects.filter(altitude__gt=self.altitude).order_by('altitude') + return Section.objects.filter(altitude__gt=self.altitude).order_by('altitude') def __str__(self): return self.name -class LevelGeometries(): - by_level_name = {} +class SectionGeometries(): + by_section_id = {} @classmethod - def by_level(cls, level, only_public=True): - return cls.by_level_name.setdefault((level.name, only_public), cls(level, only_public=only_public)) + def by_section(cls, section, only_public=True): + return cls.by_section_id.setdefault((section.id, only_public), cls(section, only_public=only_public)) - def __init__(self, level, only_public=True): - self.level = level + def __init__(self, section, only_public=True): + self.section = section self.only_public = only_public def query(self, name): - queryset = getattr(self.level, name) + queryset = getattr(self.section, name) if not self.only_public: return queryset.all() return queryset.filter(public=True) @@ -67,7 +66,7 @@ class LevelGeometries(): @cached_property def buildings(self): result = cascaded_union([building.geometry for building in self.query('buildings')]) - if self.level.intermediate: + if self.section.intermediate: result = cascaded_union([result, self.raw_rooms]) return result @@ -181,7 +180,7 @@ class LevelGeometries(): @cached_property def intermediate_shadows(self): - qs = self.query('levelconnectors').prefetch_related('levels').filter(levels__altitude__lt=self.level.altitude) + qs = self.query('levelconnectors').prefetch_related('levels').filter(levels__altitude__lt=self.section.altitude) connectors = cascaded_union([levelconnector.geometry for levelconnector in qs]) shadows = self.buildings.difference(connectors.buffer(0.4, join_style=JOIN_STYLE.mitre)) shadows = shadows.buffer(0.3) @@ -192,7 +191,7 @@ class LevelGeometries(): holes = self.holes.buffer(0.1, join_style=JOIN_STYLE.mitre) shadows = holes.difference(self.holes.buffer(-0.3, join_style=JOIN_STYLE.mitre)) - qs = self.query('levelconnectors').prefetch_related('levels').filter(levels__altitude__lt=self.level.altitude) + qs = self.query('levelconnectors').prefetch_related('levels').filter(levels__altitude__lt=self.section.altitude) connectors = cascaded_union([levelconnector.geometry for levelconnector in qs]) shadows = shadows.difference(connectors.buffer(1.0, join_style=JOIN_STYLE.mitre)) diff --git a/src/c3nav/mapdata/render/__init__.py b/src/c3nav/mapdata/render/__init__.py index cea5c070..0285e3e0 100644 --- a/src/c3nav/mapdata/render/__init__.py +++ b/src/c3nav/mapdata/render/__init__.py @@ -1,11 +1,11 @@ -from c3nav.mapdata.models import Level +from c3nav.mapdata.models.section import Section from c3nav.mapdata.render.renderer import LevelRenderer # noqa def render_all_levels(show_accessibles=False): renderers = [] - for level in Level.objects.all(): + for level in Section.objects.all(): renderers.append(LevelRenderer(level, only_public=False)) renderers.append(LevelRenderer(level, only_public=True)) diff --git a/src/c3nav/mapdata/search.py b/src/c3nav/mapdata/search.py index b3b80861..ee4432f4 100644 --- a/src/c3nav/mapdata/search.py +++ b/src/c3nav/mapdata/search.py @@ -5,17 +5,17 @@ from django.db.models import Q from c3nav.access.apply import filter_arealocations_by_access, filter_queryset_by_access from c3nav.mapdata.models import AreaLocation, LocationGroup from c3nav.mapdata.models.locations import PointLocation -from c3nav.mapdata.utils.cache import get_levels_cached +from c3nav.mapdata.utils.cache import get_sections_cached def get_location(request, location_id): - match = re.match('^c:(?P[a-z0-9-_]+):(?P[0-9]+):(?P[0-9]+)$', location_id) + match = re.match('^c:(?P
[0-9]+):(?P[0-9]+):(?P[0-9]+)$', location_id) if match: - levels = get_levels_cached() - level = levels.get(match.group('level')) - if level is None: + levels = get_sections_cached() + section = levels.get(int(match.group('section'))) + if section is None: return None - return PointLocation(level=level, x=int(match.group('x'))/100, y=int(match.group('y'))/100, request=request) + return PointLocation(section=section, x=int(match.group('x')) / 100, y=int(match.group('y')) / 100, request=request) if location_id.startswith('g:'): queryset = LocationGroup.objects.filter(Q(slug=location_id[2:], can_search=True)) diff --git a/src/c3nav/mapdata/serializers/main.py b/src/c3nav/mapdata/serializers/main.py index 3907e519..ee080adb 100644 --- a/src/c3nav/mapdata/serializers/main.py +++ b/src/c3nav/mapdata/serializers/main.py @@ -1,11 +1,12 @@ from rest_framework import serializers -from c3nav.mapdata.models import Level, Source +from c3nav.mapdata.models.section import Section +from c3nav.mapdata.models.source import Source -class LevelSerializer(serializers.ModelSerializer): +class SectionSerializer(serializers.ModelSerializer): class Meta: - model = Level + model = Section fields = ('id', 'name', 'altitude') diff --git a/src/c3nav/mapdata/utils/cache.py b/src/c3nav/mapdata/utils/cache.py index fc165611..016a16e8 100644 --- a/src/c3nav/mapdata/utils/cache.py +++ b/src/c3nav/mapdata/utils/cache.py @@ -81,10 +81,10 @@ class CachedReadOnlyViewSetMixin(): return super().retrieve(request, *args, **kwargs) -@cache_result('c3nav__mapdata__levels') -def get_levels_cached(): - from c3nav.mapdata.models import Level - return OrderedDict((level.name, level) for level in Level.objects.all()) +@cache_result('c3nav__mapdata__sections') +def get_sections_cached(): + from c3nav.mapdata.models.section import Section + return OrderedDict((section.id, section) for section in Section.objects.all()) @cache_result('c3nav__mapdata__bssids') diff --git a/src/c3nav/routing/graph.py b/src/c3nav/routing/graph.py index 95e6c5b9..3e852e2e 100644 --- a/src/c3nav/routing/graph.py +++ b/src/c3nav/routing/graph.py @@ -8,8 +8,8 @@ from django.conf import settings from scipy.sparse.csgraph._shortest_path import shortest_path from scipy.sparse.csgraph._tools import csgraph_from_dense -from c3nav.mapdata.models import Level from c3nav.mapdata.models.locations import AreaLocation, Location, LocationGroup, PointLocation +from c3nav.mapdata.models.section import Section from c3nav.routing.connection import GraphConnection from c3nav.routing.exceptions import AlreadyThere, NoRouteFound, NotYetRoutable from c3nav.routing.level import GraphLevel @@ -27,7 +27,7 @@ class Graph: def __init__(self, mtime=None): self.mtime = mtime self.levels = OrderedDict() - for level in Level.objects.all(): + for level in Section.objects.all(): self.levels[level.name] = GraphLevel(self, level) self.points = [] @@ -245,7 +245,7 @@ class Graph: def get_location_points(self, location: Location, mode): if isinstance(location, PointLocation): - points = self.levels[location.level.name].connected_points(np.array((location.x, location.y)), mode) + points = self.levels[location.section.name].connected_points(np.array((location.x, location.y)), mode) if not points: return (), None, None points, distances, ctypes = zip(*((point, distance, ctype) for point, (distance, ctype) in points.items())) diff --git a/src/c3nav/site/views.py b/src/c3nav/site/views.py index 49fb9935..2198057c 100644 --- a/src/c3nav/site/views.py +++ b/src/c3nav/site/views.py @@ -10,9 +10,9 @@ from django.utils import timezone from c3nav.access.apply import get_visible_areas from c3nav.mapdata.inclusion import get_includables_avoidables, parse_include_avoid from c3nav.mapdata.lastupdate import get_last_mapdata_update -from c3nav.mapdata.models import Level +from c3nav.mapdata.models.section import Section from c3nav.mapdata.search import get_location, search_location -from c3nav.mapdata.utils.cache import get_levels_cached +from c3nav.mapdata.utils.cache import get_sections_cached from c3nav.mapdata.utils.misc import get_dimensions, get_render_path from c3nav.routing.exceptions import AlreadyThere, NoRouteFound, NotYetRoutable from c3nav.routing.graph import Graph @@ -92,18 +92,18 @@ def main(request, location=None, origin=None, destination=None): } width, height = get_dimensions() - levels = tuple(name for name, level in get_levels_cached().items() if not level.intermediate) + sections = tuple(section for id_, section in get_sections_cached().items()) ctx.update({ 'width': width, 'height': height, 'svg_width': int(width * 6), 'svg_height': int(height * 6), - 'levels': levels, + 'sections': sections, }) map_level = request.GET.get('map-level') - if map_level in levels: + if map_level in sections: ctx.update({ 'map_level': map_level }) @@ -238,7 +238,7 @@ def main(request, location=None, origin=None, destination=None): def map_image(request, area, level): - level = get_object_or_404(Level, name=level, intermediate=False) + level = get_object_or_404(Section, name=level, intermediate=False) if area == ':base': img = get_render_path('png', level.name, 'full', True) elif area == ':full':