views.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. # -*- coding: utf-8 -*-
  2. from __future__ import unicode_literals
  3. from django.conf import settings
  4. from django.core.urlresolvers import reverse_lazy
  5. from django.http import HttpResponse, JsonResponse
  6. from django.shortcuts import render, get_object_or_404
  7. from django.utils.decorators import method_decorator
  8. from django.views.generic import CreateView, DetailView, RedirectView, ListView, TemplateView
  9. from django.views.decorators.csrf import ensure_csrf_cookie
  10. from django.contrib.auth.mixins import LoginRequiredMixin
  11. from PIL import Image, ImageDraw
  12. from .models import Point, Panorama, ReferencePoint
  13. from .forms import SelectReferencePointForm, CustomPointForm, PanoramaForm, ReferencePointForm
  14. class CelutzLoginMixin(LoginRequiredMixin):
  15. """Mixin that acts like LoginRequiredMixin if settings.LOGIN_REQUIRED is
  16. True, and does nothing otherwise. It allows to choose whether
  17. accessing celutz requires an account or is open to anybody.
  18. """
  19. login_url = '/admin/login/'
  20. def dispatch(self, request, *args, **kwargs):
  21. """Small hack: either call our parent (LoginRequiredMixin) or bypass it"""
  22. if settings.LOGIN_REQUIRED:
  23. return super(CelutzLoginMixin, self).dispatch(request, *args, **kwargs)
  24. else:
  25. return super(LoginRequiredMixin, self).dispatch(request, *args, **kwargs)
  26. class PanoramaUpload(CelutzLoginMixin, CreateView):
  27. model = Panorama
  28. fields = ('name', 'image', 'loop', 'latitude', 'longitude', 'ground_altitude', 'height_above_ground')
  29. template_name = "panorama/new.html"
  30. prefix = 'newpano'
  31. def get_success_url(self):
  32. return reverse_lazy("panorama:gen_tiles", kwargs={"pk": self.object.id})
  33. @method_decorator(ensure_csrf_cookie, name='dispatch')
  34. class PanoramaView(CelutzLoginMixin, DetailView):
  35. model = Panorama
  36. template_name = "panorama/view.html"
  37. context_object_name = "panorama"
  38. def get_context_data(self, **kwargs):
  39. context = super(PanoramaView, self).get_context_data(**kwargs)
  40. pano = context['panorama']
  41. context['panoramas'] = [p for p in Panorama.objects.all() if pano.great_circle_distance(p) <= settings.PANORAMA_MAX_DISTANCE]
  42. context['poi_list'] = [poi for poi in ReferencePoint.objects.all() if not hasattr(poi, 'panorama') and pano.great_circle_distance(poi) <= settings.PANORAMA_MAX_DISTANCE]
  43. return context
  44. class PanoramaGenTiles(CelutzLoginMixin, RedirectView):
  45. permanent = False
  46. pattern_name = "panorama:view_pano"
  47. def get_redirect_url(self, *args, **kwargs):
  48. pano = get_object_or_404(Panorama, pk=kwargs['pk'])
  49. pano.generate_tiles()
  50. return super(PanoramaGenTiles, self).get_redirect_url(*args, **kwargs)
  51. class MainView(CelutzLoginMixin, TemplateView):
  52. template_name = "panorama/main.html"
  53. def get_context_data(self, **kwargs):
  54. context = super(MainView, self).get_context_data(**kwargs)
  55. context['refpoints_form'] = SelectReferencePointForm
  56. context['custom_point_form'] = CustomPointForm
  57. context['newpanorama_form'] = PanoramaForm
  58. context['newrefpoint_form'] = ReferencePointForm
  59. context['panoramas'] = Panorama.objects.all()
  60. context['poi_list'] = [poi for poi in ReferencePoint.objects.all() if not hasattr(poi, 'panorama')]
  61. return context
  62. def compute_interesting_panoramas(self, point):
  63. """Compute all panoramas that see the given point, along with the distance
  64. and direction from each panorama towards the point. Returns a
  65. list of (panorama, distance, bearing, elevation) triples.
  66. """
  67. if isinstance(point, ReferencePoint):
  68. queryset = Panorama.objects.exclude(id=point.id)
  69. else:
  70. queryset = Panorama.objects
  71. l = [(pano, pano.line_distance(point), pano.bearing(point), pano.elevation(point))
  72. for pano in queryset.all() if pano.is_visible(point)]
  73. # Sort by increasing distance
  74. return sorted(l, key=lambda x: x[1])
  75. class CreateReferencePoint(CelutzLoginMixin, CreateView):
  76. model = ReferencePoint
  77. fields = ('name', 'latitude', 'longitude', 'ground_altitude', 'height_above_ground')
  78. template_name = 'panorama/new-refpoint.html'
  79. prefix = 'newrefpoint'
  80. def get_success_url(self):
  81. return reverse_lazy("panorama:main")
  82. class LocateReferencePointView(MainView):
  83. """Displays a located reference point"""
  84. template_name = 'panorama/locate_point.html'
  85. def post(self, request, *args, **kwargs):
  86. context = self.get_context_data()
  87. form = SelectReferencePointForm(request.POST)
  88. if form.is_valid():
  89. point = form.cleaned_data['reference_point']
  90. context['located_panoramas'] = self.compute_interesting_panoramas(point)
  91. context['located_point_name'] = point.name
  92. context['located_point_lat'] = point.latitude
  93. context['located_point_lon'] = point.longitude
  94. return super(LocateReferencePointView, self).render_to_response(context)
  95. class LocateCustomPointView(MainView):
  96. """Displays a located custom GPS point"""
  97. template_name = 'panorama/locate_point.html'
  98. def post(self, request, *args, **kwargs):
  99. context = self.get_context_data()
  100. form = CustomPointForm(request.POST)
  101. if form.is_valid():
  102. point = Point(**form.cleaned_data)
  103. context['located_panoramas'] = self.compute_interesting_panoramas(point)
  104. context['located_point_lat'] = point.latitude
  105. context['located_point_lon'] = point.longitude
  106. return super(LocateCustomPointView, self).render_to_response(context)
  107. def tile_debug_view(request, *args, **kwargs):
  108. x = kwargs['x']
  109. y = kwargs['y']
  110. z = kwargs['z']
  111. res = HttpResponse(content_type='image/jpeg')
  112. img = Image.new('RGB', (256, 256), (200, 50, 50))
  113. draw = ImageDraw.Draw(img)
  114. draw.text((50, 50), "x = " + x)
  115. draw.text((50, 100), "y = " + y)
  116. draw.text((50, 150), "z = " + z)
  117. draw.line((0, 0, 0, 255))
  118. draw.line((0, 255, 255, 255))
  119. draw.line((255, 255, 255, 0))
  120. draw.line((255, 0, 0, 0))
  121. img.save(res, format='jpeg')
  122. del draw
  123. return res