Source code for wms.views
from math import pi
import mapscript
from django.http import HttpResponse
from django.views.generic import View
from wms.maps import WmsMap
[docs]class WmsView(View):
"""WMS view class for setting up WMS endpoints"""
map_class = None
def __init__(self, **kwargs):
# Setup mapscript IO stream
mapscript.msIO_installStdoutToBuffer()
# Verify that map class has been specified correctly
if not self.map_class or not issubclass(self.map_class, WmsMap):
raise TypeError('map_class attribute is not a subclass of WmsMap. '\
'Specify map in map_class attribute.')
# Instantiate WmsMap class
self.wmsmap = self.map_class()
# Setup wms view allowing only GET requests
super(WmsView, self).__init__(http_method_names=['get'], **kwargs)
[docs] def get(self, request, *args, **kwargs):
"""
Html GET method of WmsView. This view renders WMS requests into
corresponding responses using the attached WmsMap class.
Responses are mainly images and xml files.
"""
# Setup wms request object
ows_request = mapscript.OWSRequest()
# Get ows parameters, try using tiles, otherwise use request
parameters = self.tiles()
if not parameters:
parameters = request.GET
for param, value in parameters.items():
ows_request.setParameter(param, value)
# Dynamically use host for declaring service endpoint
onlineresource = request.build_absolute_uri().split('?')[0] + '?'
self.wmsmap.map_object.setMetaData('wms_onlineresource',
onlineresource)
# Dispatch map rendering
self.wmsmap.map_object.OWSDispatch(ows_request)
# Store contenttype
contenttype = mapscript.msIO_stripStdoutBufferContentType()
# Strip buffer from headers
mapscript.msIO_stripStdoutBufferContentHeaders()
# Create response
response = HttpResponse()
# Set contenttype
response['Content-Type'] = contenttype
# Write data to response
response.write(mapscript.msIO_getStdoutBufferBytes())
return response
[docs] def get_tile_bounds(self, x, y, z):
"""
Calculates tile bounding box from Tile Map Service XYZ indices.
"""
# Setup scale factor for bounds calculations
res = 2 * pi * 6378137
shift = res / 2.0
scale = res / 2**z
# Calculate bounds
minx = x * scale - shift
maxx = (x+1) * scale - shift
miny = shift - (y+1) * scale
maxy = shift - y * scale
# Convert bounds to query string
return ','.join([repr(coord) for coord in [minx, miny, maxx, maxy]])
[docs] def tiles(self):
"""
This method checks the url parameters for xyz arguments, if found it
uses those to compute bounds for wms rendering.
"""
# Try to get tile indices from url
x = self.kwargs.get('x', '')
y = self.kwargs.get('y', '')
z = self.kwargs.get('z', '')
if not (x and y and z):
return None
else:
# Convert indices to integers
x,y,z = int(x), int(y), int(z)
# Get the tile bounds
tilebounds = self.get_tile_bounds(x,y,z)
# Get layers to draw from url
layers = self.kwargs.get('layers')
# Get image format from url
format = {'.png': 'image/png',
'.jpg': 'image/jpeg'}[self.kwargs.get('format')]
# Setup wms parameter object
return {
'SERVICE': 'WMS',
'REQUEST': 'GetMap',
'VERSION': '1.1.1',
'TRANSPARENT': 'true',
'HEIGHT': '256',
'WIDTH': '256',
'SRS': 'EPSG:3857',
'FORMAT': format,
'LAYERS': layers,
'BBOX': tilebounds
}