rename and refactor mapdata models

This commit is contained in:
Laura Klünder 2017-05-05 12:32:35 +02:00
parent a18dc108c1
commit 5973ca3211
10 changed files with 86 additions and 84 deletions

View file

@ -100,6 +100,6 @@ def create_editor_form(mapitemtype):
def create_editor_forms(): def create_editor_forms():
from c3nav.mapdata.models.base import MAPITEM_TYPES from c3nav.mapdata.models.base import FEATURE_TYPES
for mapitemtype in MAPITEM_TYPES.values(): for mapitemtype in FEATURE_TYPES.values():
create_editor_form(mapitemtype) create_editor_form(mapitemtype)

View file

@ -5,7 +5,7 @@ from django.shortcuts import get_object_or_404, redirect, render
from c3nav.access.apply import can_access, filter_queryset_by_access from c3nav.access.apply import can_access, filter_queryset_by_access
from c3nav.mapdata.models import AreaLocation from c3nav.mapdata.models import AreaLocation
from c3nav.mapdata.models.base import MAPITEM_TYPES from c3nav.mapdata.models.base import FEATURE_TYPES
def list_mapitemtypes(request, level): def list_mapitemtypes(request, level):
@ -26,13 +26,13 @@ def list_mapitemtypes(request, level):
'title': mapitemtype._meta.verbose_name_plural, 'title': mapitemtype._meta.verbose_name_plural,
'has_level': hasattr(mapitemtype, 'level') or hasattr(mapitemtype, 'levels'), 'has_level': hasattr(mapitemtype, 'level') or hasattr(mapitemtype, 'levels'),
'count': get_item_count(mapitemtype), 'count': get_item_count(mapitemtype),
} for name, mapitemtype in MAPITEM_TYPES.items() } for name, mapitemtype in FEATURE_TYPES.items()
], ],
}) })
def list_mapitems(request, mapitem_type, level=None): def list_mapitems(request, mapitem_type, level=None):
mapitemtype = MAPITEM_TYPES.get(mapitem_type) mapitemtype = FEATURE_TYPES.get(mapitem_type)
if mapitemtype is None: if mapitemtype is None:
raise Http404('Unknown mapitemtype.') raise Http404('Unknown mapitemtype.')
@ -68,7 +68,7 @@ def list_mapitems(request, mapitem_type, level=None):
def edit_mapitem(request, mapitem_type, name=None): def edit_mapitem(request, mapitem_type, name=None):
mapitemtype = MAPITEM_TYPES.get(mapitem_type) mapitemtype = FEATURE_TYPES.get(mapitem_type)
if mapitemtype is None: if mapitemtype is None:
raise Http404() raise Http404()

View file

@ -10,7 +10,7 @@ from rest_framework.viewsets import ReadOnlyModelViewSet, ViewSet
from c3nav.access.apply import filter_arealocations_by_access, filter_queryset_by_access 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.lastupdate import get_last_mapdata_update
from c3nav.mapdata.models import GEOMETRY_MAPITEM_TYPES, AreaLocation, Level, LocationGroup, Source from c3nav.mapdata.models import GEOMETRY_FEATURE_TYPES, AreaLocation, Level, LocationGroup, Source
from c3nav.mapdata.models.geometry import Stair from c3nav.mapdata.models.geometry import Stair
from c3nav.mapdata.search import get_location from c3nav.mapdata.search import get_location
from c3nav.mapdata.serializers.main import LevelSerializer, SourceSerializer from c3nav.mapdata.serializers.main import LevelSerializer, SourceSerializer
@ -29,7 +29,7 @@ class GeometryTypeViewSet(ViewSet):
('name', name), ('name', name),
('title', str(mapitemtype._meta.verbose_name)), ('title', str(mapitemtype._meta.verbose_name)),
('title_plural', str(mapitemtype._meta.verbose_name_plural)), ('title_plural', str(mapitemtype._meta.verbose_name_plural)),
)) for name, mapitemtype in GEOMETRY_MAPITEM_TYPES.items() )) for name, mapitemtype in GEOMETRY_FEATURE_TYPES.items()
]) ])
@ -40,7 +40,7 @@ class GeometryViewSet(ViewSet):
""" """
def list(self, request): def list(self, request):
types = set(request.GET.getlist('type')) types = set(request.GET.getlist('type'))
valid_types = list(GEOMETRY_MAPITEM_TYPES.keys()) valid_types = list(GEOMETRY_FEATURE_TYPES.keys())
if not types: if not types:
types = valid_types types = valid_types
else: else:
@ -68,7 +68,7 @@ class GeometryViewSet(ViewSet):
def _list(self, request, types, level): def _list(self, request, types, level):
results = [] results = []
for t in types: for t in types:
mapitemtype = GEOMETRY_MAPITEM_TYPES[t] mapitemtype = GEOMETRY_FEATURE_TYPES[t]
queryset = mapitemtype.objects.all() queryset = mapitemtype.objects.all()
if level: if level:
if hasattr(mapitemtype, 'level'): if hasattr(mapitemtype, 'level'):

View file

@ -1,5 +1,6 @@
from .level import Level # noqa from .level import Level # noqa
from .source import Source # noqa from .source import Source # noqa
from .collections import Elevator # noqa from .collections import Elevator # noqa
from .geometry import GeometryMapItemWithLevel, GEOMETRY_MAPITEM_TYPES # noqa from .geometry import LevelFeature # noqa
from c3nav.mapdata.models.base import GEOMETRY_FEATURE_TYPES
from .locations import AreaLocation, LocationGroup # noqa from .locations import AreaLocation, LocationGroup # noqa

View file

@ -4,21 +4,34 @@ from django.db import models
from django.db.models.base import ModelBase from django.db.models.base import ModelBase
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils.translation import get_language from django.utils.translation import get_language
from shapely.geometry import mapping, Point
from c3nav.mapdata.fields import GeometryField
from c3nav.mapdata.lastupdate import set_last_mapdata_update from c3nav.mapdata.lastupdate import set_last_mapdata_update
from c3nav.mapdata.utils.json import format_geojson
MAPITEM_TYPES = OrderedDict() FEATURE_TYPES = OrderedDict()
GEOMETRY_FEATURE_TYPES = OrderedDict()
LEVEL_FEATURE_TYPES = OrderedDict()
AREA_FEATURE_TYPES = OrderedDict()
class MapItemMeta(ModelBase): class FeatureBase(ModelBase):
def __new__(mcs, name, bases, attrs): def __new__(mcs, name, bases, attrs):
cls = super().__new__(mcs, name, bases, attrs) cls = super().__new__(mcs, name, bases, attrs)
if not cls._meta.abstract and name != 'Source': if not cls._meta.abstract and name != 'Source':
MAPITEM_TYPES[name.lower()] = cls FEATURE_TYPES[name.lower()] = cls
if hasattr(cls, 'geometry'):
GEOMETRY_FEATURE_TYPES[name.lower()] = cls
if hasattr(cls, 'level'):
LEVEL_FEATURE_TYPES[name.lower()] = cls
if hasattr(cls, 'area'):
AREA_FEATURE_TYPES[name.lower()] = cls
return cls return cls
class MapItem(models.Model, metaclass=MapItemMeta): class Feature(models.Model, metaclass=FeatureBase):
name = models.SlugField(_('Name'), unique=True, max_length=50) name = models.SlugField(_('Name'), unique=True, max_length=50)
EditorForm = None EditorForm = None
@ -42,3 +55,34 @@ class MapItem(models.Model, metaclass=MapItemMeta):
class Meta: class Meta:
abstract = True abstract = True
class GeometryFeature(Feature):
"""
A map feature with a geometry
"""
geometry = GeometryField()
geomtype = None
class Meta:
abstract = True
def get_geojson_properties(self):
return OrderedDict((
('type', self.__class__.__name__.lower()),
('name', self.name),
))
def to_geojson(self):
return OrderedDict((
('type', 'Feature'),
('properties', self.get_geojson_properties()),
('geometry', format_geojson(mapping(self.geometry), round=False)),
))
def get_shadow_geojson(self):
return None
def contains(self, x, y):
return self.geometry.contains(Point(x, y))

View file

@ -1,9 +1,9 @@
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from c3nav.mapdata.models.base import MapItem from c3nav.mapdata.models.base import Feature
class Elevator(MapItem): class Elevator(Feature):
""" """
An elevator. An elevator.
""" """

View file

@ -1,61 +1,18 @@
from collections import OrderedDict from collections import OrderedDict
from django.db import models from django.db import models
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from shapely.geometry import CAP_STYLE, JOIN_STYLE, Point from shapely.geometry import CAP_STYLE, JOIN_STYLE
from shapely.geometry.geo import mapping from shapely.geometry.geo import mapping
from c3nav.mapdata.fields import GeometryField
from c3nav.mapdata.models import Elevator from c3nav.mapdata.models import Elevator
from c3nav.mapdata.models.base import MapItem, MapItemMeta from c3nav.mapdata.models.base import GeometryFeature
from c3nav.mapdata.utils.json import format_geojson from c3nav.mapdata.utils.json import format_geojson
GEOMETRY_MAPITEM_TYPES = OrderedDict()
class LevelFeature(GeometryFeature):
class GeometryMapItemMeta(MapItemMeta):
def __new__(mcs, name, bases, attrs):
cls = super().__new__(mcs, name, bases, attrs)
if not cls._meta.abstract:
GEOMETRY_MAPITEM_TYPES[name.lower()] = cls
return cls
class GeometryMapItem(MapItem, metaclass=GeometryMapItemMeta):
""" """
A map feature a map feature that has a geometry and belongs to a level
"""
geometry = GeometryField()
geomtype = None
class Meta:
abstract = True
def get_geojson_properties(self):
return OrderedDict((
('type', self.__class__.__name__.lower()),
('name', self.name),
))
def to_geojson(self):
return OrderedDict((
('type', 'Feature'),
('properties', self.get_geojson_properties()),
('geometry', format_geojson(mapping(self.geometry), round=False)),
))
def get_shadow_geojson(self):
return None
def contains(self, x, y):
return self.geometry.contains(Point(x, y))
class GeometryMapItemWithLevel(GeometryMapItem):
"""
A map feature
""" """
level = models.ForeignKey('mapdata.Level', on_delete=models.CASCADE, verbose_name=_('level')) level = models.ForeignKey('mapdata.Level', on_delete=models.CASCADE, verbose_name=_('level'))
@ -68,9 +25,9 @@ class GeometryMapItemWithLevel(GeometryMapItem):
return result return result
class GeometryMapItemWithArea(GeometryMapItem): class AreaFeature(GeometryFeature):
""" """
A map feature a map feature that has a geometry and belongs to an area
""" """
area = models.ForeignKey('mapdata.Area', on_delete=models.CASCADE, verbose_name=_('area')) area = models.ForeignKey('mapdata.Area', on_delete=models.CASCADE, verbose_name=_('area'))
@ -83,7 +40,7 @@ class GeometryMapItemWithArea(GeometryMapItem):
return result return result
class Building(GeometryMapItemWithLevel): class Building(LevelFeature):
""" """
The outline of a building on a specific level The outline of a building on a specific level
""" """
@ -95,7 +52,7 @@ class Building(GeometryMapItemWithLevel):
default_related_name = 'buildings' default_related_name = 'buildings'
class Area(GeometryMapItemWithLevel): class Area(LevelFeature):
""" """
An accessible area. Shouldn't overlap. An accessible area. Shouldn't overlap.
""" """
@ -128,7 +85,7 @@ class Area(GeometryMapItemWithLevel):
return result return result
class StuffedArea(GeometryMapItemWithArea): class StuffedArea(AreaFeature):
""" """
A slow area with many tables or similar. Avoid it from routing by slowing it a bit down A slow area with many tables or similar. Avoid it from routing by slowing it a bit down
""" """
@ -140,7 +97,7 @@ class StuffedArea(GeometryMapItemWithArea):
default_related_name = 'stuffedareas' default_related_name = 'stuffedareas'
class Escalator(GeometryMapItemWithArea): class Escalator(AreaFeature):
""" """
An escalator area An escalator area
""" """
@ -163,7 +120,7 @@ class Escalator(GeometryMapItemWithArea):
return result return result
class Stair(GeometryMapItemWithArea): class Stair(AreaFeature):
""" """
A stair A stair
""" """
@ -197,7 +154,7 @@ class Stair(GeometryMapItemWithArea):
)) ))
class Obstacle(GeometryMapItemWithArea): class Obstacle(AreaFeature):
""" """
An obstacle An obstacle
""" """
@ -218,7 +175,7 @@ class Obstacle(GeometryMapItemWithArea):
return result return result
class LineObstacle(GeometryMapItemWithArea): class LineObstacle(AreaFeature):
""" """
An obstacle that is a line with a specific width An obstacle that is a line with a specific width
""" """
@ -248,7 +205,7 @@ class LineObstacle(GeometryMapItemWithArea):
return result return result
class Door(GeometryMapItemWithLevel): class Door(LevelFeature):
""" """
A connection between two rooms A connection between two rooms
""" """
@ -260,7 +217,7 @@ class Door(GeometryMapItemWithLevel):
default_related_name = 'doors' default_related_name = 'doors'
class Hole(GeometryMapItemWithLevel): class Hole(LevelFeature):
""" """
A hole in the ground of a room, e.g. for stairs. A hole in the ground of a room, e.g. for stairs.
""" """
@ -272,7 +229,7 @@ class Hole(GeometryMapItemWithLevel):
default_related_name = 'holes' default_related_name = 'holes'
class ElevatorLevel(GeometryMapItemWithLevel): class ElevatorLevel(LevelFeature):
""" """
An elevator Level An elevator Level
""" """

View file

@ -4,11 +4,11 @@ from django.utils.translation import ugettext_lazy as _
from shapely.geometry import CAP_STYLE, JOIN_STYLE from shapely.geometry import CAP_STYLE, JOIN_STYLE
from shapely.ops import cascaded_union from shapely.ops import cascaded_union
from c3nav.mapdata.models.base import MapItem from c3nav.mapdata.models.base import Feature
from c3nav.mapdata.utils.geometry import assert_multilinestring, assert_multipolygon from c3nav.mapdata.utils.geometry import assert_multilinestring, assert_multipolygon
class Level(MapItem): class Level(Feature):
""" """
A map level (-1, 0, 1, 2) A map level (-1, 0, 1, 2)
""" """

View file

@ -10,8 +10,8 @@ from django.utils.translation import ungettext_lazy
from c3nav.mapdata.fields import JSONField, validate_bssid_lines from c3nav.mapdata.fields import JSONField, validate_bssid_lines
from c3nav.mapdata.lastupdate import get_last_mapdata_update from c3nav.mapdata.lastupdate import get_last_mapdata_update
from c3nav.mapdata.models import Level from c3nav.mapdata.models import Level
from c3nav.mapdata.models.base import MapItem from c3nav.mapdata.models.base import Feature
from c3nav.mapdata.models.geometry import GeometryMapItemWithLevel from c3nav.mapdata.models.geometry import LevelFeature
class Location: class Location:
@ -43,7 +43,7 @@ class LocationModelMixin(Location):
return self._meta.verbose_name return self._meta.verbose_name
class LocationGroup(LocationModelMixin, MapItem): class LocationGroup(LocationModelMixin, Feature):
titles = JSONField() titles = JSONField()
can_search = models.BooleanField(default=True, verbose_name=_('can be searched')) can_search = models.BooleanField(default=True, verbose_name=_('can be searched'))
can_describe = models.BooleanField(default=True, verbose_name=_('can be used to describe a position')) can_describe = models.BooleanField(default=True, verbose_name=_('can be used to describe a position'))
@ -99,7 +99,7 @@ class LocationGroup(LocationModelMixin, MapItem):
return result return result
class AreaLocation(LocationModelMixin, GeometryMapItemWithLevel): class AreaLocation(LocationModelMixin, LevelFeature):
LOCATION_TYPES = ( LOCATION_TYPES = (
('level', _('Level')), ('level', _('Level')),
('area', _('General Area')), ('area', _('General Area')),

View file

@ -1,10 +1,10 @@
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from c3nav.mapdata.models.base import MapItem from c3nav.mapdata.models.base import Feature
class Source(MapItem): class Source(Feature):
""" """
A map source, images of levels that can be useful as backgrounds for the map editor A map source, images of levels that can be useful as backgrounds for the map editor
""" """