cut altitude areas

This commit is contained in:
Laura Klünder 2017-08-05 14:17:24 +02:00
parent 9ca07be935
commit cb4a4c1b33
3 changed files with 70 additions and 2 deletions

View file

@ -0,0 +1,9 @@
from django.core.management.base import BaseCommand
class Command(BaseCommand):
help = 'recalculate the map altitudes'
def handle(self, *args, **options):
from c3nav.mapdata.models import AltitudeArea
AltitudeArea.recalculate()

View file

@ -1,7 +1,7 @@
from c3nav.mapdata.models.access import AccessRestriction # noqa from c3nav.mapdata.models.access import AccessRestriction # noqa
from c3nav.mapdata.models.level import Level # noqa from c3nav.mapdata.models.level import Level # noqa
from c3nav.mapdata.models.geometry.level import Building, Space, Door # 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 # noqa from c3nav.mapdata.models.geometry.space import Area, Stair, Obstacle, LineObstacle, Hole, AltitudeMarker # noqa
from c3nav.mapdata.models.locations import Location, LocationSlug, LocationGroup, LocationGroupCategory # noqa from c3nav.mapdata.models.locations import Location, LocationSlug, LocationGroup, LocationGroupCategory # noqa
from c3nav.mapdata.models.source import Source # noqa from c3nav.mapdata.models.source import Source # noqa
from c3nav.mapdata.models.update import MapUpdate # noqa from c3nav.mapdata.models.update import MapUpdate # noqa

View file

@ -1,11 +1,13 @@
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 shapely.ops import cascaded_union
from c3nav.mapdata.fields import GeometryField from c3nav.mapdata.fields import GeometryField
from c3nav.mapdata.models import Level from c3nav.mapdata.models import Level
from c3nav.mapdata.models.access import AccessRestrictionMixin from c3nav.mapdata.models.access import AccessRestrictionMixin
from c3nav.mapdata.models.geometry.base import GeometryMixin from c3nav.mapdata.models.geometry.base import GeometryMixin
from c3nav.mapdata.models.locations import SpecificLocation from c3nav.mapdata.models.locations import SpecificLocation
from c3nav.mapdata.utils.geometry import assert_multilinestring, assert_multipolygon
class LevelGeometryMixin(GeometryMixin): class LevelGeometryMixin(GeometryMixin):
@ -80,3 +82,60 @@ class AltitudeArea(LevelGeometryMixin, models.Model):
verbose_name = _('Altitude Area') verbose_name = _('Altitude Area')
verbose_name_plural = _('Altitude Areas') verbose_name_plural = _('Altitude Areas')
default_related_name = 'altitudeareas' default_related_name = 'altitudeareas'
@classmethod
def recalculate(cls):
levels = Level.objects.prefetch_related('buildings', 'doors', 'spaces', 'spaces__columns',
'spaces__obstacles', 'spaces__lineobstacles', 'spaces__holes',
'spaces__stairs', 'spaces__altitudemarkers')
for level in levels:
areas = []
stairs = []
spaces = {}
buildings_geom = cascaded_union(tuple(building.geometry for building in level.buildings.all()))
for space in level.spaces.all():
if space.outside:
space.geometry = space.geometry.difference(buildings_geom)
spaces[space.pk] = space
area = space.geometry
buffered = space.geometry.buffer(0.0001)
remove = cascaded_union(tuple(c.geometry for c in space.columns.all()) +
tuple(o.geometry for o in space.obstacles.all()) +
tuple(o.buffered_geometry for o in space.lineobstacles.all()) +
tuple(h.geometry for h in space.holes.all()))
areas.extend(assert_multipolygon(space.geometry.difference(remove)))
for stair in space.stairs.all():
stairs.extend(assert_multilinestring(stair.geometry.intersection(buffered).difference(remove)))
areas = assert_multipolygon(cascaded_union(areas+list(door.geometry for door in level.doors.all())))
areas = [AltitudeArea(geometry=area, level=level) for area in areas]
for area in areas:
area.spaces = set()
area.connected_to = []
for space in level.spaces.all():
if area.geometry.intersects(space.geometry):
area.spaces.add(space.pk)
for stair in stairs:
for i, area in enumerate(tuple(areas)):
if not stair.intersects(area.geometry):
continue
divided = assert_multipolygon(area.geometry.difference(stair.buffer(0.0001)))
if len(divided) > 2:
raise ValueError
area.geometry = divided[0]
if len(divided) == 2:
new_area = AltitudeArea(geometry=divided[1], level=level)
new_area.spaces = area.spaces
new_area.connected_to = [area]
area.connected_to.append(new_area)
areas.append(new_area)
for subarea in (area, new_area):
subarea.spaces = set(space for space in subarea.spaces
if spaces[space].geometry.intersects(subarea.geometry))
break