From 97c9c7ecb75c23d4ae4be57bca3e9bf82bfde44e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laura=20Kl=C3=BCnder?= Date: Mon, 11 Dec 2023 18:17:39 +0100 Subject: [PATCH] make altitudes reusable using GroundAltitude model --- src/c3nav/editor/forms.py | 5 ++++- src/c3nav/editor/urls.py | 1 + src/c3nav/editor/views/edit.py | 13 +++++++++++++ src/c3nav/mapdata/models/__init__.py | 1 + src/c3nav/mapdata/models/altitudes.py | 19 +++++++++++++++++++ src/c3nav/mapdata/models/geometry/level.py | 5 +++-- src/c3nav/mapdata/models/geometry/space.py | 9 +++++++-- src/c3nav/mapdata/utils/dataformats.py | 0 8 files changed, 48 insertions(+), 5 deletions(-) create mode 100644 src/c3nav/mapdata/models/altitudes.py create mode 100644 src/c3nav/mapdata/utils/dataformats.py diff --git a/src/c3nav/editor/forms.py b/src/c3nav/editor/forms.py index 9c50bb90..fed452c2 100644 --- a/src/c3nav/editor/forms.py +++ b/src/c3nav/editor/forms.py @@ -136,6 +136,9 @@ class EditorFormBase(I18nModelFormMixin, ModelForm): if 'category' in self.fields: self.fields['category'].label_from_instance = attrgetter('title') + if 'groundaltitude' in self.fields: + self.fields['groundaltitude'].label_from_instance = attrgetter('title') + if 'label_settings' in self.fields: self.fields['label_settings'].label_from_instance = attrgetter('title') @@ -289,7 +292,7 @@ def create_editor_form(editor_model): 'walk', 'ordering', 'category', 'width', 'groups', 'height', 'color', 'priority', 'hierarchy', 'icon_name', 'base_altitude', 'waytype', 'access_restriction', 'default_height', 'door_height', 'outside', 'can_search', 'can_describe', 'geometry', 'single', 'altitude', 'short_label', - 'origin_space', 'target_space', 'data', 'comment', 'slow_down_factor', '' + 'origin_space', 'target_space', 'data', 'comment', 'slow_down_factor', 'groundaltitude', 'extra_seconds', 'speed', 'description', 'speed_up', 'description_up', 'enter_description', 'level_change_description', 'base_mapdata_accessible', 'can_report_missing', 'label_settings', 'label_override', 'min_zoom', 'max_zoom', 'font_size', diff --git a/src/c3nav/editor/urls.py b/src/c3nav/editor/urls.py index 48c2a032..84fa8fb9 100644 --- a/src/c3nav/editor/urls.py +++ b/src/c3nav/editor/urls.py @@ -59,6 +59,7 @@ urlpatterns.extend(add_editor_urls('LocationGroupCategory')) urlpatterns.extend(add_editor_urls('LocationGroup')) urlpatterns.extend(add_editor_urls('DynamicLocation')) urlpatterns.extend(add_editor_urls('WayType')) +urlpatterns.extend(add_editor_urls('GroundAltitude')) urlpatterns.extend(add_editor_urls('AccessRestriction')) urlpatterns.extend(add_editor_urls('AccessRestrictionGroup')) urlpatterns.extend(add_editor_urls('Source')) diff --git a/src/c3nav/editor/views/edit.py b/src/c3nav/editor/views/edit.py index f0acad21..ddc4fee8 100644 --- a/src/c3nav/editor/views/edit.py +++ b/src/c3nav/editor/views/edit.py @@ -51,6 +51,7 @@ def main_index(request): 'child_models': [ child_model(request, 'LocationGroupCategory'), child_model(request, 'LocationGroup'), + child_model(request, 'GroundAltitude'), child_model(request, 'DynamicLocation'), child_model(request, 'WayType'), child_model(request, 'AccessRestriction'), @@ -472,6 +473,10 @@ def list_objects(request, model=None, level=None, space=None, explicit_edit=Fals model._meta.get_field('target_space') queryset = queryset.select_related('target_space') + with suppress(FieldDoesNotExist): + model._meta.get_field('altitude') + add_cols.append('altitude') + ctx.update({ 'levels': Level.objects.filter(Level.q_for_request(request), on_top_of__isnull=True), 'level': space.level, @@ -492,6 +497,14 @@ def list_objects(request, model=None, level=None, space=None, explicit_edit=Fals add_cols.append('priority') queryset = queryset.order_by('-priority') + with suppress(FieldDoesNotExist): + model._meta.get_field('altitude') + add_cols.append('altitude') + + with suppress(FieldDoesNotExist): + model._meta.get_field('groundaltitude') + queryset = queryset.select_related('groundaltitude') + ctx.update({ 'back_url': reverse('editor.index'), 'back_title': _('back to overview'), diff --git a/src/c3nav/mapdata/models/__init__.py b/src/c3nav/mapdata/models/__init__.py index 20ae3182..6a539399 100644 --- a/src/c3nav/mapdata/models/__init__.py +++ b/src/c3nav/mapdata/models/__init__.py @@ -1,5 +1,6 @@ from c3nav.mapdata.models.update import MapUpdate # noqa from c3nav.mapdata.models.access import AccessRestriction # noqa +from c3nav.mapdata.models.altitudes import GroundAltitude # noqa from c3nav.mapdata.models.level import Level # noqa from c3nav.mapdata.models.geometry.level import Building, Space, Door, AltitudeArea # noqa from c3nav.mapdata.models.geometry.space import Area, Stair, Obstacle, LineObstacle, Hole, AltitudeMarker # noqa diff --git a/src/c3nav/mapdata/models/altitudes.py b/src/c3nav/mapdata/models/altitudes.py new file mode 100644 index 00000000..00d3947f --- /dev/null +++ b/src/c3nav/mapdata/models/altitudes.py @@ -0,0 +1,19 @@ +from django.db import models +from django.utils.translation import gettext_lazy as _ + + +class GroundAltitude(models.Model): + """ + A pre-defined ground altitude + """ + name = models.CharField(_('Name'), unique=True, max_length=70) # a slugfield would forbid periods + altitude = models.DecimalField(_('altitude'), null=False, max_digits=6, decimal_places=2) + + class Meta: + verbose_name = _('Ground Altitude') + verbose_name_plural = _('Ground altitudes') + default_related_name = "groundaltitudes" + + @property + def title(self): + return f'{self.name} ({self.altitude}m)' diff --git a/src/c3nav/mapdata/models/geometry/level.py b/src/c3nav/mapdata/models/geometry/level.py index 3e5e66a5..950b08ca 100644 --- a/src/c3nav/mapdata/models/geometry/level.py +++ b/src/c3nav/mapdata/models/geometry/level.py @@ -218,7 +218,8 @@ class AltitudeArea(LevelGeometryMixin, models.Model): spaces = {} levels = Level.objects.prefetch_related('buildings', 'doors', 'spaces', 'spaces__columns', 'spaces__obstacles', 'spaces__lineobstacles', 'spaces__holes', - 'spaces__stairs', 'spaces__ramps', 'spaces__altitudemarkers') + 'spaces__stairs', 'spaces__ramps', + 'spaces__altitudemarkers__groundaltitude') logger = logging.getLogger('c3nav') for level in levels: @@ -285,7 +286,7 @@ class AltitudeArea(LevelGeometryMixin, models.Model): # give altitudes to areas for space in level.spaces.all(): - for altitudemarker in space.altitudemarkers.all(): + for altitudemarker in space.altitudemarkers.select_related('groundaltitude').all(): for area in space_areas[space.pk]: if area.geometry_prep.contains(unwrap_geom(altitudemarker.geometry)): area.altitude = altitudemarker.altitude diff --git a/src/c3nav/mapdata/models/geometry/space.py b/src/c3nav/mapdata/models/geometry/space.py index 45b8e30c..be869439 100644 --- a/src/c3nav/mapdata/models/geometry/space.py +++ b/src/c3nav/mapdata/models/geometry/space.py @@ -298,16 +298,21 @@ class AltitudeMarker(SpaceGeometryMixin, models.Model): An altitude marker """ geometry = GeometryField('point') - altitude = models.DecimalField(_('altitude'), null=False, max_digits=6, decimal_places=2) + groundaltitude = models.ForeignKey('mapdata.GroundAltitude', on_delete=models.CASCADE, + verbose_name=_('altitude')) class Meta: verbose_name = _('Altitude Marker') verbose_name_plural = _('Altitude Markers') default_related_name = 'altitudemarkers' + @property + def altitude(self) -> Decimal: + return self.groundaltitude.altitude + @property def title(self): - return '%s (%sm)' % (super().title, self.altitude) + return f'#{self.pk}: {self.groundaltitude.title}' class LeaveDescription(SerializableMixin): diff --git a/src/c3nav/mapdata/utils/dataformats.py b/src/c3nav/mapdata/utils/dataformats.py new file mode 100644 index 00000000..e69de29b