thanhleviet
7/4/2012 - 7:25 AM

geojson tiles views.py

geojson tiles views.py

from redistricting.apps.features.models import CensusBlock, CensusTract, CensusCounty, DataBlock
from redistricting.utils import gmerc

from django.http import HttpResponse, Http404, HttpResponseForbidden
from django.contrib.gis.geos import GEOSGeometry

from django.shortcuts import render_to_response
from django.template.loader import render_to_string
from django.template import RequestContext

from django.core import serializers
from django.views.decorators.cache import cache_page

import json
import time

# def blocks_by_bounds(request):
#     """
#     /geom/CensusBlocksBox/?bbox=42.864637,-88.891514,42.94645,-79.43732
#     """
#     return features_bounds(request, DataBlock)

# def tracts_by_bounds(request):
#     return features_bounds(request, CensusTract)

# def features_bounds(request, GeomClass):
#     """
#     /geom/<FeatureType>sBox/?bbox=42.864637,-88.891514,42.94645,-79.43732
#     """
#     bbox = request.GET.get('bbox', '')
#     jsonpcallback = request.GET.get('callback','')
#     if bbox == '':
#         raise Http404


#     # has lat lngs in this order: SWNE
#     bbox = bbox.split(',')

#     # TODO: to ease scaling, will probably have to round these off and memcached the result
#     bbox_wkt = "POLYGON(("
#     bbox_wkt += bbox[1]+" "+bbox[0]+","
#     bbox_wkt += bbox[1]+" "+bbox[2]+","
#     bbox_wkt += bbox[3]+" "+bbox[2]+","
#     bbox_wkt += bbox[3]+" "+bbox[0]+","
#     bbox_wkt += bbox[1]+" "+bbox[0]
#     bbox_wkt += "))"
#     box_geom = GEOSGeometry(bbox_wkt, srid=4326)

#     cbs = GeomClass.objects.filter(the_geom__intersects = box_geom)
#     return _output_geo_queryset(cbs, jsonpcallback)


@cache_page(60*60*24*7)
def serve_block_tiles(request, z, x, y):
    """
    /geom/CensusBlockTile/<z>/<x>/<y>.json

    For example:
    /geom/CensusBlockTile/16/19302/24633.json
    """
    z,x,y = [int(z), int(x), int(y)]

    assert isinstance(z, int), TypeError("zoom must be an int from 0 to 30")
    assert isinstance(x, int), TypeError("x must be an int")
    assert isinstance(y, int), TypeError("y must be an int")

    if (z < 13):
        return HttpResponse(json.dumps([]), mimetype="application/json")
    else:
        return serve_tile(request, z, x, y, DataBlock)

def serve_tile(request, z, x, y, GeomClass):
    """
    /geom/<FeatureType>Tile/<z>/<x>/<y>.json
    """
    jsonpcallback = request.GET.get('callback','')


    # Translate tile coordinates into lat-lng bounds
    x1 = x * 256
    x2 = x1 + 255
    y1 = y * 256
    y2 = y1 + 255
    n, w = gmerc.px2ll(x1, y1, z)
    s, e = gmerc.px2ll(x2, y2, z)
    s,w,n,e = [str(s), str(w), str(n), str(e)]
    bbox_wkt = "".join(["POLYGON((",
                        w+" "+s+",",
                        w+" "+n+",",
                        e+" "+n+",",
                        e+" "+s+",",
                        w+" "+s,
                        "))"])
    
    box_geom = GEOSGeometry(bbox_wkt, srid=4326)

    cbs = GeomClass.objects.filter(the_geom__intersects = box_geom)
    return _output_geo_queryset(cbs, jsonpcallback)



def _output_geo_queryset(qs, jsonpcallback=""):
    """
    Helper function that takes a query set and returns the geometries and info as json.
    Uses a JSONP callback if one is specified
    """

    #Bleh. this bit is pretty ugly
    try:
        geoms = { "type": "FeatureCollection",
                  "features": [{ 'id': c.geoid10, 'type': 'Feature', 'geometry': json.loads(c.the_geom.json), 'properties': serializers.serialize('python', [c])[0]['fields'] } for c in qs]
                  }
        if (len(geoms) == 0):
            return HttpResponse(json.dumps([]), mimetype="application/json")
        assert('totpop' in geoms['features'][0]['properties']), AttributeError("Doesn't have population info")
    except AttributeError:
        geoms = { "type": "FeatureCollection",
                  "features": [{ 'id': c.geoid10, 'geometry': json.loads(c.the_geom.json), 'properties': None } for c in qs]
                  }
        
    if (jsonpcallback != ''):
        out = jsonpcallback + '(' + json.dumps(geoms) + ')'
    else:
        out = json.dumps(geoms)
    
    resp = HttpResponse(out, mimetype="application/json")
    resp['X-ALBERT'] = "=)"
    return resp