cut altitude areas
This commit is contained in:
parent
9ca07be935
commit
cb4a4c1b33
3 changed files with 70 additions and 2 deletions
9
src/c3nav/mapdata/management/commands/buildaltitudes.py
Normal file
9
src/c3nav/mapdata/management/commands/buildaltitudes.py
Normal 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()
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue