
from clusterlizard.clusterer import Clusterer
from django.http import HttpResponse
from djangopeople.models import *

import simplejson
import math


def latlong_to_mercator(lat, long):
    x = long * 20037508.34 / 180
    y = math.log(math.tan((90 + lat) * math.pi / 360)) / (math.pi / 180)
    y = y * 20037508.34 / 180;
    return x, y


def mercator_to_latlong(x, y):
    long = (x / 20037508.34) * 180
    lat = (y / 20037508.34) * 180
    lat = 180/math.pi * (2 * math.atan(math.exp(lat * math.pi / 180)) - math.pi / 2)
    return lat, long


def input_generator():
    """
    The input to ClusterLizard should be a generator that yields (mx,my,id) tuples.
    This function reads them from the DjangoPeople models.
    """
    for person in DjangoPerson.objects.all():
        mx, my = latlong_to_mercator(person.latitude, person.longitude)
        yield (mx, my, person.id)
    
    
def save_clusters(clusters, zoom):
    """
    The output function provided to ClusterLizard should be a
    function that takes 'clusters', a set of clusters, and 'zoom',
    the integer Google zoom level.
    """
    for cluster in clusters:
        lat, long = mercator_to_latlong(*cluster.mean)
        ClusteredPoint.objects.create(
            latitude = lat,
            longitude = long,
            number = len(cluster),
            zoom = zoom,
            djangoperson_id = len(cluster) == 1 and list(cluster.points)[0][2] or None,
        )


def progress(done, left, took, zoom, eta):
    """
    You can also pass in an optional progress callback.
    """
    print "Iter %s (%s clusters) [%.3f secs] [zoom: %s] [ETA %s]" % (done, left, took, zoom, eta)
    

def as_json(request, x1, y1, x2, y2, z):
    """
    View that returns clusters for the given zoom level as JSON.
    """
    x1, y1, x2, y2 = map(float, (x1, y1, x2, y2))
    if x1 > x2:
        x1, x2 = x2, x1
    if y1 > y2:
        y1, y2 = y2, y1
    points = []
    for cluster in ClusteredPoint.objects.filter(latitude__gt=y1, latitude__lt=y2, longitude__gt=x1, longitude__lt=x2, zoom=z):
        if cluster.djangoperson:
            points.append((cluster.longitude, cluster.latitude, cluster.number, cluster.djangoperson.get_absolute_url()))
        else:
            points.append((cluster.longitude, cluster.latitude, cluster.number, None))
    return HttpResponse(simplejson.dumps(points))
    


def run():
    """
    Runs the clustering, clearing the DB first.
    """
    ClusteredPoint.objects.all().delete()
    clusterer = Clusterer(
        input_generator(),
        save_clusters,
        progress,
    )
    clusterer.run()
@@ -40,16 +40,17 @@
 usterer%0A
+%0A
 from dja
@@ -111,16 +111,47 @@
 import *
+%0Afrom django.db.models import Q
 %0A%0Aimport
@@ -1716,25 +1716,25 @@
 quest, x
-1
+2
 , y1, x
-2
+1
 , y2, z)
@@ -1877,14 +1877,14 @@
  if 
-x
+y
 1 %3E 
-x
+y
 2:%0A 
@@ -1894,31 +1894,36 @@
     
-x1, x
+y1, y
 2 = 
-x2, x1
+y2, y1%0A    
 %0A    if 
 y1 %3E
@@ -1922,75 +1922,230 @@
  if 
-y1 %3E y2:%0A        y1, y2 = y2, y1%0A    points = %5B%5D%0A    for cluster in
+x1 %3C x2: # View not crossing the date line%0A        query = ClusteredPoint.objects.filter(latitude__gt=y1, latitude__lt=y2, longitude__gt=x1, longitude__lt=x2, zoom=z)%0A    else: # View crossing the date line%0A        query =
  Clu
@@ -2175,46 +2175,53 @@
 ter(
-lat
+Q(long
 itude__
-gt=y1, lat
+lt=x1) %7C Q(long
 itude__
-lt=y
+gt=x
 2, l
-ong
+at
 itud
@@ -2222,32 +2222,31 @@
 atitude__gt=
-x
+y
 1, l
-ong
+at
 itude__lt=x2
@@ -2235,34 +2235,35 @@
 1, latitude__lt=
-x2
+y2)
 , zoom=z):%0A     
@@ -2255,16 +2255,62 @@
  zoom=z)
+%0A    %0A    points = %5B%5D%0A    for cluster in query
 :%0A      

Fix panning the map over the International Date Line.