From 0496575d257932cdc9ad51da620ac4544f42c082 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laura=20Kl=C3=BCnder?= Date: Mon, 28 Nov 2016 20:56:52 +0100 Subject: [PATCH] add elevators --- src/c3nav/editor/forms.py | 2 +- src/c3nav/editor/static/editor/js/editor.js | 3 +- .../migrations/0007_auto_20161128_1903.py | 61 +++++++++++++++++++ src/c3nav/mapdata/models/__init__.py | 1 + src/c3nav/mapdata/models/collections.py | 16 +++++ src/c3nav/mapdata/models/geometry.py | 42 +++++++++++++ src/c3nav/mapdata/models/level.py | 16 +++-- src/c3nav/mapdata/packageio/const.py | 4 +- src/c3nav/mapdata/packageio/read.py | 3 +- src/c3nav/mapdata/render/renderer.py | 3 + 10 files changed, 143 insertions(+), 8 deletions(-) create mode 100644 src/c3nav/mapdata/migrations/0007_auto_20161128_1903.py create mode 100644 src/c3nav/mapdata/models/collections.py diff --git a/src/c3nav/editor/forms.py b/src/c3nav/editor/forms.py index f8d70554..ed99bcd8 100644 --- a/src/c3nav/editor/forms.py +++ b/src/c3nav/editor/forms.py @@ -80,7 +80,7 @@ class MapitemFormMixin(ModelForm): def create_editor_form(mapitemtype): - possible_fields = ['name', 'package', 'level', 'geometry', 'height'] + possible_fields = ['name', 'package', 'level', 'geometry', 'height', 'elevator', 'button'] existing_fields = [field for field in possible_fields if hasattr(mapitemtype, field)] class EditorForm(MapitemFormMixin, ModelForm): diff --git a/src/c3nav/editor/static/editor/js/editor.js b/src/c3nav/editor/static/editor/js/editor.js index fda02bbe..04497cc7 100644 --- a/src/c3nav/editor/static/editor/js/editor.js +++ b/src/c3nav/editor/static/editor/js/editor.js @@ -157,7 +157,8 @@ editor = { 'room': '#FFFFFF', 'outside': '#EEFFEE', 'obstacle': '#999999', - 'door': '#FF00FF' + 'door': '#FF00FF', + 'elevatorlevel': '#9EF8FB' }, _get_geometry_style: function (feature) { // style callback for GeoJSON loader diff --git a/src/c3nav/mapdata/migrations/0007_auto_20161128_1903.py b/src/c3nav/mapdata/migrations/0007_auto_20161128_1903.py new file mode 100644 index 00000000..4cfd1308 --- /dev/null +++ b/src/c3nav/mapdata/migrations/0007_auto_20161128_1903.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.2 on 2016-11-28 19:03 +from __future__ import unicode_literals + +import c3nav.mapdata.fields +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('mapdata', '0006_auto_20161128_1809'), + ] + + operations = [ + migrations.CreateModel( + name='Elevator', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.SlugField(unique=True, verbose_name='Name')), + ('package', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='elevators', to='mapdata.Package', verbose_name='map package')), + ], + options={ + 'default_related_name': 'elevators', + 'verbose_name': 'Elevator', + 'verbose_name_plural': 'Elevators', + }, + ), + migrations.CreateModel( + name='ElevatorLevel', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.SlugField(unique=True, verbose_name='Name')), + ('geometry', c3nav.mapdata.fields.GeometryField()), + ('button', models.SlugField(max_length=10, verbose_name='Button label')), + ('elevator', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='levels', to='mapdata.Elevator')), + ('level', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='elevatorlevels', to='mapdata.Level', verbose_name='level')), + ('package', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='elevatorlevels', to='mapdata.Package', verbose_name='map package')), + ], + options={ + 'default_related_name': 'elevatorlevels', + 'verbose_name': 'Elevator Level', + 'verbose_name_plural': 'Elevator Levels', + }, + ), + migrations.AlterModelOptions( + name='room', + options={'verbose_name': 'Room', 'verbose_name_plural': 'Rooms'}, + ), + migrations.AlterField( + model_name='room', + name='level', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='rooms', to='mapdata.Level', verbose_name='level'), + ), + migrations.AlterField( + model_name='room', + name='package', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='rooms', to='mapdata.Package', verbose_name='map package'), + ), + ] diff --git a/src/c3nav/mapdata/models/__init__.py b/src/c3nav/mapdata/models/__init__.py index f705959e..575317d0 100644 --- a/src/c3nav/mapdata/models/__init__.py +++ b/src/c3nav/mapdata/models/__init__.py @@ -1,4 +1,5 @@ from .level import Level # noqa from .package import Package # noqa from .source import Source # noqa +from .collections import Elevator # noqa from .geometry import GeometryMapItem, GEOMETRY_MAPITEM_TYPES # noqa diff --git a/src/c3nav/mapdata/models/collections.py b/src/c3nav/mapdata/models/collections.py new file mode 100644 index 00000000..5e2dd0ff --- /dev/null +++ b/src/c3nav/mapdata/models/collections.py @@ -0,0 +1,16 @@ +from django.utils.translation import ugettext_lazy as _ + +from c3nav.mapdata.models.base import MapItem + + +class Elevator(MapItem): + """ + An elevator. + """ + class Meta: + verbose_name = _('Elevator') + verbose_name_plural = _('Elevators') + default_related_name = 'elevators' + + def __str__(self): + return self.name diff --git a/src/c3nav/mapdata/models/geometry.py b/src/c3nav/mapdata/models/geometry.py index 22d9e12e..e1b3db68 100644 --- a/src/c3nav/mapdata/models/geometry.py +++ b/src/c3nav/mapdata/models/geometry.py @@ -5,6 +5,7 @@ from django.utils.translation import ugettext_lazy as _ from shapely.geometry.geo import mapping, shape from c3nav.mapdata.fields import GeometryField +from c3nav.mapdata.models import Elevator from c3nav.mapdata.models.base import MapItem, MapItemMeta from c3nav.mapdata.utils import format_geojson @@ -162,3 +163,44 @@ class Door(GeometryMapItem): verbose_name = _('Door') verbose_name_plural = _('Doors') default_related_name = 'doors' + + +class ElevatorLevel(GeometryMapItem): + """ + An elevator Level + """ + elevator = models.ForeignKey(Elevator, on_delete=models.PROTECT, related_name='levels') + button = models.SlugField(_('Button label'), max_length=10) + + geomtype = 'polygon' + + class Meta: + verbose_name = _('Elevator Level') + verbose_name_plural = _('Elevator Levels') + default_related_name = 'elevatorlevels' + + def get_geojson_properties(self): + result = super().get_geojson_properties() + result['elevator'] = self.elevator.name + result['button'] = self.button + return result + + @classmethod + def fromfile(cls, data, file_path): + kwargs = super().fromfile(data, file_path) + + if 'elevator' not in data: + raise ValueError('missing elevator.') + kwargs['elevator'] = data['elevator'] + + if 'button' not in data: + raise ValueError('missing button.') + kwargs['button'] = data['button'] + + return kwargs + + def tofile(self): + result = super().tofile() + result['elevator'] = self.elevator.name + result['button'] = self.button + return result diff --git a/src/c3nav/mapdata/models/level.py b/src/c3nav/mapdata/models/level.py index 3e74857f..f37e181f 100644 --- a/src/c3nav/mapdata/models/level.py +++ b/src/c3nav/mapdata/models/level.py @@ -57,7 +57,7 @@ class LevelGeometries(): @cached_property def rooms(self): - return cascaded_union([room.geometry for room in self.level.rooms.all()]).intersection(self.buildings) + return cascaded_union([room.geometry for room in self.level.rooms.all()]) @cached_property def outsides(self): @@ -75,13 +75,21 @@ class LevelGeometries(): def raw_doors(self): return cascaded_union([door.geometry for door in self.level.doors.all()]).intersection(self.mapped) + @cached_property + def elevatorlevels(self): + return cascaded_union([elevatorlevel.geometry for elevatorlevel in self.level.elevatorlevels.all()]) + + @cached_property + def areas(self): + return cascaded_union([self.rooms, self.outsides, self.elevatorlevels]).intersection(self.buildings) + @cached_property def areas_and_doors(self): - return cascaded_union([self.rooms, self.raw_doors]) + return cascaded_union([self.areas, self.raw_doors]) @cached_property def walls(self): - return self.buildings.difference(self.rooms) + return self.buildings.difference(self.areas) @cached_property def walls_without_doors(self): @@ -93,4 +101,4 @@ class LevelGeometries(): @cached_property def doors(self): - return self.raw_doors.difference(self.rooms).difference(self.outsides) + return self.raw_doors.difference(self.areas) diff --git a/src/c3nav/mapdata/packageio/const.py b/src/c3nav/mapdata/packageio/const.py index 7b8bd0ab..05297dee 100644 --- a/src/c3nav/mapdata/packageio/const.py +++ b/src/c3nav/mapdata/packageio/const.py @@ -1,4 +1,6 @@ from c3nav.mapdata.models import Level, Package, Source -from c3nav.mapdata.models.geometry import Building, Door, Obstacle, Outside, Room +from c3nav.mapdata.models.collections import Elevator +from c3nav.mapdata.models.geometry import Building, Door, ElevatorLevel, Obstacle, Outside, Room ordered_models = (Package, Level, Source, Building, Room, Outside, Door, Obstacle) +ordered_models += (Elevator, ElevatorLevel) diff --git a/src/c3nav/mapdata/packageio/read.py b/src/c3nav/mapdata/packageio/read.py index 7db8bfd6..a8d54e4a 100644 --- a/src/c3nav/mapdata/packageio/read.py +++ b/src/c3nav/mapdata/packageio/read.py @@ -7,7 +7,7 @@ from collections import OrderedDict from django.conf import settings from django.core.management import CommandError -from c3nav.mapdata.models import Level, Package +from c3nav.mapdata.models import Elevator, Level, Package from c3nav.mapdata.packageio.const import ordered_models @@ -146,6 +146,7 @@ class ReaderItem: relations = { 'level': Level, + 'elevator': Elevator, } def save(self): diff --git a/src/c3nav/mapdata/render/renderer.py b/src/c3nav/mapdata/render/renderer.py index e629095e..07f2172e 100644 --- a/src/c3nav/mapdata/render/renderer.py +++ b/src/c3nav/mapdata/render/renderer.py @@ -87,6 +87,9 @@ class LevelRenderer(): stroke_color='#9E9E9E', stroke_width=3)) + contents.append(self.polygon_svg(self.level.geometries.elevatorlevels, + fill_color='#9EF8FB')) + contents.append(self.polygon_svg(self.level.geometries.walls_without_doors, fill_color='#949494', stroke_color='#757575',