views.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  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 .models import Point, Panorama, ReferencePoint
  12. from .forms import SelectReferencePointForm, CustomPointForm, PanoramaForm, ReferencePointForm
  13. class CelutzLoginMixin(LoginRequiredMixin):
  14. """Mixin that acts like LoginRequiredMixin if settings.LOGIN_REQUIRED is
  15. True, and does nothing otherwise. It allows to choose whether
  16. accessing celutz requires an account or is open to anybody.
  17. """
  18. login_url = '/admin/login/'
  19. def dispatch(self, request, *args, **kwargs):
  20. """Small hack: either call our parent (LoginRequiredMixin) or bypass it"""
  21. if settings.LOGIN_REQUIRED:
  22. return super(CelutzLoginMixin, self).dispatch(request, *args, **kwargs)
  23. else:
  24. return super(LoginRequiredMixin, self).dispatch(request, *args, **kwargs)
  25. class PanoramaUpload(CelutzLoginMixin, CreateView):
  26. model = Panorama
  27. fields = ('name', 'image', 'loop', 'latitude', 'longitude', 'ground_altitude', 'height_above_ground')
  28. template_name = "panorama/new.html"
  29. prefix = 'newpano'
  30. def get_success_url(self):
  31. return reverse_lazy("panorama:gen_tiles", kwargs={"pk": self.object.id})
  32. @method_decorator(ensure_csrf_cookie, name='dispatch')
  33. class PanoramaView(CelutzLoginMixin, DetailView):
  34. model = Panorama
  35. template_name = "panorama/view.html"
  36. context_object_name = "panorama"
  37. def get_context_data(self, **kwargs):
  38. context = super(PanoramaView, self).get_context_data(**kwargs)
  39. pano = context['panorama']
  40. context['panoramas'] = [p for p in Panorama.objects.all() if pano.great_circle_distance(p) <= settings.PANORAMA_MAX_DISTANCE]
  41. 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]
  42. return context
  43. class PanoramaGenTiles(CelutzLoginMixin, RedirectView):
  44. permanent = False
  45. pattern_name = "panorama:view_pano"
  46. def get_redirect_url(self, *args, **kwargs):
  47. pano = get_object_or_404(Panorama, pk=kwargs['pk'])
  48. pano.generate_tiles()
  49. return super(PanoramaGenTiles, self).get_redirect_url(*args, **kwargs)
  50. class MainView(CelutzLoginMixin, TemplateView):
  51. template_name = "panorama/main.html"
  52. def get_context_data(self, **kwargs):
  53. context = super(MainView, self).get_context_data(**kwargs)
  54. context['refpoints_form'] = SelectReferencePointForm
  55. context['custom_point_form'] = CustomPointForm
  56. context['newpanorama_form'] = PanoramaForm
  57. context['newrefpoint_form'] = ReferencePointForm
  58. context['panoramas'] = Panorama.objects.all()
  59. context['poi_list'] = [poi for poi in ReferencePoint.objects.all() if not hasattr(poi, 'panorama')]
  60. return context
  61. def compute_interesting_panoramas(self, point):
  62. """Compute all panoramas that see the given point, along with the distance
  63. and direction from each panorama towards the point. Returns a
  64. list of (panorama, distance, bearing, elevation) triples.
  65. """
  66. if isinstance(point, ReferencePoint):
  67. queryset = Panorama.objects.exclude(id=point.id)
  68. else:
  69. queryset = Panorama.objects
  70. l = [(pano, pano.line_distance(point), pano.bearing(point), pano.elevation(point))
  71. for pano in queryset.all() if pano.is_visible(point) and pano.great_circle_distance(point) <= settings.LOCATE_POINT_MAX_DISTANCE]
  72. # Sort by increasing distance
  73. return sorted(l, key=lambda x: x[1])
  74. class CreateReferencePoint(CelutzLoginMixin, CreateView):
  75. model = ReferencePoint
  76. fields = ('name', 'latitude', 'longitude', 'ground_altitude', 'height_above_ground')
  77. template_name = 'panorama/new-refpoint.html'
  78. prefix = 'newrefpoint'
  79. def get_success_url(self):
  80. return reverse_lazy("panorama:main")
  81. class LocateReferencePointView(MainView):
  82. """Displays a located reference point"""
  83. template_name = 'panorama/locate_point.html'
  84. def post(self, request, *args, **kwargs):
  85. context = self.get_context_data()
  86. form = SelectReferencePointForm(request.POST)
  87. if form.is_valid():
  88. point = form.cleaned_data['reference_point']
  89. context['located_panoramas'] = self.compute_interesting_panoramas(point)
  90. context['located_point_name'] = point.name
  91. context['located_point_lat'] = point.latitude
  92. context['located_point_lon'] = point.longitude
  93. return super(LocateReferencePointView, self).render_to_response(context)
  94. class LocateCustomPointView(MainView):
  95. """Displays a located custom GPS point"""
  96. template_name = 'panorama/locate_point.html'
  97. def post(self, request, *args, **kwargs):
  98. context = self.get_context_data()
  99. form = CustomPointForm(request.POST)
  100. if form.is_valid():
  101. point = Point(**form.cleaned_data)
  102. context['located_panoramas'] = self.compute_interesting_panoramas(point)
  103. context['located_point_lat'] = point.latitude
  104. context['located_point_lon'] = point.longitude
  105. return super(LocateCustomPointView, self).render_to_response(context)