views.py 5.3 KB

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