PageRenderTime 29ms CodeModel.GetById 21ms app.highlight 6ms RepoModel.GetById 1ms app.codeStats 0ms

/online/index.py

http://gpxplot.googlecode.com/
Python | 136 lines | 119 code | 14 blank | 3 comment | 22 complexity | f6cd8ca75b3085bc764cfb9404a96393 MD5 | raw file
  1#!/usr/bin/env python
  2# vim: set fileencoding=utf-8 noexpandtab ts=4 sw=4 :
  3
  4from google.appengine.ext import webapp
  5from google.appengine.ext.webapp.util import run_wsgi_app
  6from google.appengine.ext.webapp import template
  7from google.appengine.runtime.apiproxy_errors import OverQuotaError
  8
  9from django.utils import simplejson as json
 10
 11import urllib2
 12import logging
 13
 14from gpxplot import parse_gpx_data,google_chart_url,var_dist,var_ele
 15
 16max_gpx_size = 1048576
 17
 18class GPXSizeError (Exception):
 19	pass
 20
 21class NoAltitudeData (Exception):
 22    pass
 23
 24def plot_on_request(request):
 25	"Process POST request with GPX data. Return a URL of the plot."
 26	imperial=request.get('imperial')
 27	if imperial == 'on':
 28		metric=False
 29	else:
 30		metric=True
 31	logging.debug('metric='+str(metric))
 32	try:
 33		url=request.get("gpxurl")
 34		if url: # fetch GPX data
 35			logging.debug('fetching GPX from '+url)
 36			reader=urllib2.urlopen(url)
 37			gpxsize = int(reader.headers["Content-Length"])
 38			logging.debug('gpxsize=%d' % gpxsize)
 39			if gpxsize > max_gpx_size:
 40				raise GPXSizeError("File is too large")
 41			gpxdata=reader.read()
 42		else:
 43			logging.debug('using submitted GPX data')
 44			gpxdata=request.get("gpxfile")
 45			gpxsize=len(gpxdata)
 46			logging.debug('gpxsize=%d' % gpxsize)
 47			if gpxsize > max_gpx_size:
 48				raise GPXSizeError("File is too large")
 49		logging.debug('gpxdata='+gpxdata[:320])
 50	except Exception, e:
 51		logging.debug(unicode(e))
 52		raise e
 53	if len(gpxdata) == 0:
 54		raise Exception("There is no GPX data to plot!")
 55	# reduce number of points gradually, to fit URL length
 56	npoints=700
 57	url=None
 58	while not url:
 59		try:
 60			trk=parse_gpx_data(gpxdata,npoints=npoints)
 61			y=var_ele
 62			max_ele=max([max([p[y] for p in s]) for s in trk if len(s) > 0])
 63			min_ele=min([min([p[y] for p in s]) for s in trk if len(s) > 0])
 64			if abs(max_ele) < 1e-3 and abs(min_ele) < 1e-3:
 65				msg = 'File does not contain altitude data ' \
 66						+ 'or it is flat sea level. Nothing to plot.'
 67				raise NoAltitudeData(msg)
 68			url=google_chart_url(trk,var_dist,var_ele,metric=metric)
 69		except OverflowError, e:
 70			npoints -= 100
 71			if npoints <= 0:
 72				raise e
 73	return url
 74
 75class MainPage(webapp.RequestHandler):
 76	def get(self):
 77		content={'title':'Visualize GPX profile online',
 78				'form':True,'bg':'#efefff'}
 79		self.response.out.write(template.render('index.html',content))
 80
 81	def post(self):
 82		content={'title':'Elevation??istance profile','form':False, 'bg':'#fff'}
 83		try:
 84			url=plot_on_request(self.request)
 85			content['imgsrc']=url
 86		except GPXSizeError, e:
 87			msg = 'File is too large to be processed on gpxplot.appspot.com. ' + \
 88				  '<br/>Reduce file size with gpsbabel or plot it offline with a ' + \
 89				  'stand-alone version of gpxplot.'
 90			content['error'] = msg
 91			logging.error(e)
 92		except NoAltitudeData, e:
 93			content['error'] = e.message
 94			logging.error(e)
 95		except OverQuotaError, e:
 96			msg = 'Application exceeded free quota. Try again later.'
 97			content['error'] = msg
 98			logging.error(e)
 99		except Exception, e:
100			msg = 'Your GPX track cannot be processed. Sorry.'
101			msg += '<br/>'+unicode(e)
102			content['error'] = msg
103			content['bugreportme'] = True
104			logging.error(e)
105		self.response.out.write(template.render('index.html',content))
106
107class ApiHandler(webapp.RequestHandler):
108	"Return a URL of the image in a file."
109	def get(self):
110		return self.post()
111	def post(self):
112		try:
113			url=plot_on_request(self.request)
114			format=self.request.get("output","json")
115			if format == "json":
116				self.response.headers['Content-Type']='application/json'
117				self.response.out.write(json.dumps({'url':url}))
118			elif format == "png":
119				self.redirect(url)
120			else:
121				raise Exception("Output format not supported.")
122		except Exception, e:
123			self.response.set_status(400,message='Exception: '+unicode(e))
124
125application = webapp.WSGIApplication(
126		 [('/', MainPage),
127		  (r'/api/0.1/plot',ApiHandler),
128		  (r'/api/0.1.1/plot',ApiHandler),
129		  (r'/api/0.1.2/plot',ApiHandler),
130		 ], debug=True)
131
132def main():
133	run_wsgi_app(application)
134
135if __name__ == "__main__":
136	main()