team-3/src/c3nav/editor/api.py

114 lines
4.9 KiB
Python
Raw Normal View History

from itertools import chain
2017-05-26 21:26:37 +02:00
from rest_framework.decorators import list_route
from rest_framework.exceptions import ValidationError
from rest_framework.generics import get_object_or_404
from rest_framework.response import Response
from rest_framework.viewsets import ViewSet
from shapely.ops import cascaded_union
from c3nav.mapdata.models import Area, Section, Space
class EditorViewSet(ViewSet):
"""
Editor API
/geometries/ returns a list of geojson features, you have to specify ?section=<id> or ?space=<id>
/geometrystyles/ returns styling information for all geometry types
"""
@list_route(methods=['get'])
def geometries(self, request, *args, **kwargs):
section = request.GET.get('section')
space = request.GET.get('space')
if section is not None:
if space is not None:
raise ValidationError('Only section or space can be specified.')
section = get_object_or_404(Section, pk=section)
buildings = section.buildings.all()
buildings_geom = cascaded_union([building.geometry for building in buildings])
2017-06-09 15:22:30 +02:00
spaces = {space.id: space for space in section.spaces.all().prefetch_related('groups', 'holes', 'columns')}
holes_geom = []
for space in spaces.values():
if space.outside:
space.geometry = space.geometry.difference(buildings_geom)
else:
space.geometry = space.geometry.intersection(buildings_geom)
2017-06-09 15:22:30 +02:00
columns_geom = cascaded_union([column.geometry for column in space.columns.all()])
space.geometry = space.geometry.difference(columns_geom)
space_holes_geom = cascaded_union([hole.geometry for hole in space.holes.all()])
holes_geom.append(space_holes_geom.intersection(space.geometry))
space.geometry = space.geometry.difference(space_holes_geom)
holes_geom = cascaded_union(holes_geom)
for building in buildings:
building.original_geometry = building.geometry
for obj in chain(buildings, (s for s in spaces.values() if s.level == 'normal')):
obj.geometry = obj.geometry.difference(holes_geom)
results = []
def add_spaces(level):
results.extend(space for space in spaces.values() if space.level == level)
areas = Area.objects.filter(space__section=section, space__level=level).prefetch_related('groups')
areas = [area for area in areas if area.get_color()]
for area in areas:
area.geometry = area.geometry.intersection(spaces[area.space_id].geometry)
results.extend((area for area in areas if not area.geometry.is_empty))
add_spaces('lower')
results.extend(buildings)
for door in section.doors.all():
results.append(door)
add_spaces('normal')
add_spaces('upper')
return Response([obj.to_geojson() for obj in results])
elif space is not None:
space = get_object_or_404(Space.objects.select_related('section'), pk=space)
section = space.section
doors = [door for door in section.doors.all() if door.geometry.intersects(space.geometry)]
doors_geom = cascaded_union([door.geometry for door in doors])
spaces = [s for s in section.spaces.filter(level='normal').prefetch_related('groups')
if s.geometry.intersects(doors_geom) and s.pk != space.pk]
2017-05-27 16:19:49 +02:00
space.bounds = True
results = chain(
section.buildings.all(),
doors,
[space],
space.areas.all().prefetch_related('groups'),
2017-06-08 15:19:12 +02:00
space.holes.all(),
space.stairs.all(),
space.obstacles.all(),
space.lineobstacles.all(),
2017-06-09 15:22:30 +02:00
space.columns.all(),
space.points.all().prefetch_related('groups'),
2017-06-09 15:22:30 +02:00
spaces,
)
2017-05-22 00:12:49 +02:00
return Response(sum([self._get_geojsons(obj) for obj in results], ()))
else:
raise ValidationError('No section or space specified.')
2017-05-22 00:12:49 +02:00
def _get_geojsons(self, obj):
return ((obj.to_shadow_geojson(),) if hasattr(obj, 'to_shadow_geojson') else ()) + (obj.to_geojson(),)
@list_route(methods=['get'])
def geometrystyles(self, request, *args, **kwargs):
return Response({
'building': '#929292',
'space': '#d1d1d1',
'hole': 'rgba(255, 0, 0, 0.3)',
'door': '#ffffff',
2017-05-27 19:01:38 +02:00
'area': 'rgba(85, 170, 255, 0.2)',
2017-05-22 00:12:49 +02:00
'stair': 'rgba(160, 0, 160, 0.5)',
'obstacle': '#999999',
'lineobstacle': '#999999',
2017-06-09 15:22:30 +02:00
'column': '#888888',
'point': '#4488cc',
2017-05-22 00:12:49 +02:00
'shadow': '#000000',
})