PaxHeader/tilecache-2.11 000755 777777 777777 00000000257 11456036476 017125 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142718
20 atime=1287142716
38 LIBARCHIVE.creationtime=1287142716
24 SCHILY.dev=234881029
22 SCHILY.ino=3311395
19 SCHILY.nlink=16
tilecache-2.11/ 000755 473017214730172100000000000 11456036476 015360 5 ustar 00christos christos 000000 000000 tilecache-2.11/PaxHeader/dev.ini 000644 777777 777777 00000000210 11205506201 020417 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142718
20 atime=1287142718
24 SCHILY.dev=234881029
22 SCHILY.ino=3311466
18 SCHILY.nlink=1
tilecache-2.11/dev.ini 000644 473017214730172100000000441 11205506201 016612 0 ustar 00christos christos 000000 000000 [server:main]
#tested with Paste#http and PasteScript#wsgiutils, PasteScript#twisted also possible
use = egg:PasteScript#cherrypy
host = 127.0.0.1
port = 5000
[composite:main]
use = egg:Paste#urlmap
/tc = tilecache1
[app:tilecache1]
use = egg:TileCache
tilecache_config = tilecache.cfg
tilecache-2.11/PaxHeader/docs 000755 777777 777777 00000000257 11456036476 020055 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142718
20 atime=1287142717
38 LIBARCHIVE.creationtime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311445
19 SCHILY.nlink=16
tilecache-2.11/docs/ 000755 473017214730172100000000000 11456036476 016310 5 ustar 00christos christos 000000 000000 tilecache-2.11/PaxHeader/ez_setup.py 000644 777777 777777 00000000210 10733205325 021360 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311443
18 SCHILY.nlink=1
tilecache-2.11/ez_setup.py 000644 473017214730172100000021400 10733205325 017551 0 ustar 00christos christos 000000 000000 #!python
"""Bootstrap setuptools installation
If you want to use setuptools in your package's setup.py, just include this
file in the same directory with it, and add this to the top of your setup.py::
from ez_setup import use_setuptools
use_setuptools()
If you want to require a specific version of setuptools, set a download
mirror, or use an alternate download directory, you can do so by supplying
the appropriate options to ``use_setuptools()``.
This file can also be run as a script to install or upgrade setuptools.
"""
import sys
DEFAULT_VERSION = "0.6c7"
DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3]
md5_data = {
'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',
'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',
'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',
'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',
'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',
'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',
'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',
'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',
'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',
'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',
'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27',
'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277',
'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa',
'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e',
'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e',
'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f',
'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2',
'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc',
'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167',
'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64',
'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d',
'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20',
'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab',
'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53',
'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2',
'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e',
'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372',
}
import sys, os
def _validate_md5(egg_name, data):
if egg_name in md5_data:
from md5 import md5
digest = md5(data).hexdigest()
if digest != md5_data[egg_name]:
print >>sys.stderr, (
"md5 validation of %s failed! (Possible download problem?)"
% egg_name
)
sys.exit(2)
return data
def use_setuptools(
version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
download_delay=15
):
"""Automatically find/download setuptools and make it available on sys.path
`version` should be a valid setuptools version number that is available
as an egg for download under the `download_base` URL (which should end with
a '/'). `to_dir` is the directory where setuptools will be downloaded, if
it is not already available. If `download_delay` is specified, it should
be the number of seconds that will be paused before initiating a download,
should one be required. If an older version of setuptools is installed,
this routine will print a message to ``sys.stderr`` and raise SystemExit in
an attempt to abort the calling script.
"""
try:
import setuptools
if setuptools.__version__ == '0.0.1':
print >>sys.stderr, (
"You have an obsolete version of setuptools installed. Please\n"
"remove it from your system entirely before rerunning this script."
)
sys.exit(2)
except ImportError:
egg = download_setuptools(version, download_base, to_dir, download_delay)
sys.path.insert(0, egg)
import setuptools; setuptools.bootstrap_install_from = egg
import pkg_resources
try:
pkg_resources.require("setuptools>="+version)
except pkg_resources.VersionConflict, e:
# XXX could we install in a subprocess here?
print >>sys.stderr, (
"The required version of setuptools (>=%s) is not available, and\n"
"can't be installed while this script is running. Please install\n"
" a more recent version first.\n\n(Currently using %r)"
) % (version, e.args[0])
sys.exit(2)
def download_setuptools(
version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
delay = 15
):
"""Download setuptools from a specified location and return its filename
`version` should be a valid setuptools version number that is available
as an egg for download under the `download_base` URL (which should end
with a '/'). `to_dir` is the directory where the egg will be downloaded.
`delay` is the number of seconds to pause before an actual download attempt.
"""
import urllib2, shutil
egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3])
url = download_base + egg_name
saveto = os.path.join(to_dir, egg_name)
src = dst = None
if not os.path.exists(saveto): # Avoid repeated downloads
try:
from distutils import log
if delay:
log.warn("""
---------------------------------------------------------------------------
This script requires setuptools version %s to run (even to display
help). I will attempt to download it for you (from
%s), but
you may need to enable firewall access for this script first.
I will start the download in %d seconds.
(Note: if this machine does not have network access, please obtain the file
%s
and place it in this directory before rerunning this script.)
---------------------------------------------------------------------------""",
version, download_base, delay, url
); from time import sleep; sleep(delay)
log.warn("Downloading %s", url)
src = urllib2.urlopen(url)
# Read/write all in one block, so we don't create a corrupt file
# if the download is interrupted.
data = _validate_md5(egg_name, src.read())
dst = open(saveto,"wb"); dst.write(data)
finally:
if src: src.close()
if dst: dst.close()
return os.path.realpath(saveto)
def main(argv, version=DEFAULT_VERSION):
"""Install or upgrade setuptools and EasyInstall"""
try:
import setuptools
except ImportError:
egg = None
try:
egg = download_setuptools(version, delay=0)
sys.path.insert(0,egg)
from setuptools.command.easy_install import main
return main(list(argv)+[egg]) # we're done here
finally:
if egg and os.path.exists(egg):
os.unlink(egg)
else:
if setuptools.__version__ == '0.0.1':
# tell the user to uninstall obsolete version
use_setuptools(version)
req = "setuptools>="+version
import pkg_resources
try:
pkg_resources.require(req)
except pkg_resources.VersionConflict:
try:
from setuptools.command.easy_install import main
except ImportError:
from easy_install import main
main(list(argv)+[download_setuptools(delay=0)])
sys.exit(0) # try to force an exit
else:
if argv:
from setuptools.command.easy_install import main
main(argv)
else:
print "Setuptools version",version,"or greater has been installed."
print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
def update_md5(filenames):
"""Update our built-in md5 registry"""
import re
from md5 import md5
for name in filenames:
base = os.path.basename(name)
f = open(name,'rb')
md5_data[base] = md5(f.read()).hexdigest()
f.close()
data = [" %r: %r,\n" % it for it in md5_data.items()]
data.sort()
repl = "".join(data)
import inspect
srcfile = inspect.getsourcefile(sys.modules[__name__])
f = open(srcfile, 'rb'); src = f.read(); f.close()
match = re.search("\nmd5_data = {\n([^}]+)}", src)
if not match:
print >>sys.stderr, "Internal error!"
sys.exit(2)
src = src[:match.start(1)] + repl + src[match.end(1):]
f = open(srcfile,'w')
f.write(src)
f.close()
if __name__=='__main__':
if len(sys.argv)>2 and sys.argv[1]=='--md5update':
update_md5(sys.argv[2:])
else:
main(sys.argv[1:])
tilecache-2.11/PaxHeader/index.html 000644 777777 777777 00000000210 10733214415 021145 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142718
20 atime=1287142718
24 SCHILY.dev=234881029
22 SCHILY.ino=3311464
18 SCHILY.nlink=1
tilecache-2.11/index.html 000644 473017214730172100000002113 10733214415 017336 0 ustar 00christos christos 000000 000000
tilecache-2.11/PaxHeader/setup.py 000644 777777 777777 00000000210 11456031665 020671 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311444
18 SCHILY.nlink=1
tilecache-2.11/setup.py 000644 473017214730172100000003233 11456031665 017066 0 ustar 00christos christos 000000 000000 #!/usr/bin/env python
import sys
try:
from setuptools import setup
except:
from ez_setup import use_setuptools
use_setuptools()
from setuptools import setup
readme = file('docs/README.txt','rb').read()
classifiers = [
'Development Status :: 4 - Beta',
'Intended Audience :: Developers',
'Intended Audience :: Science/Research',
'License :: OSI Approved :: BSD License',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Topic :: Scientific/Engineering :: GIS',
]
# We'd like to let debian install the /etc/tilecache.cfg,
# but put them in tilecache/tilecache.cfg using setuptools
# otherwise.
extra = { }
if "--debian" in sys.argv:
extra['data_files']=[('/etc', ['tilecache.cfg']),('.',['dev.ini'])]
sys.argv.remove("--debian")
else:
extra['data_files']=[('TileCache', ['tilecache.cfg']),('.',['dev.ini'])]
setup(name='TileCache',
version='2.11',
description='a web map tile caching system',
author='TileCache Contributors',
author_email='tilecache@lists.osgeo.org',
url='http://tilecache.org/',
long_description=readme,
packages=['TileCache', 'TileCache.Caches', 'TileCache.Services', 'TileCache.Layers'],
scripts=['tilecache.cgi', 'tilecache.fcgi',
'tilecache_seed.py', 'tilecache_install_config.py',
'tilecache_clean.py', 'tilecache_http_server.py'],
zip_safe=False,
test_suite = 'tests.run_doc_tests',
license="BSD",
classifiers=classifiers,
entry_points = """
[paste.app_factory]
main = TileCache.Service:paste_deploy_app
""",
**extra
)
tilecache-2.11/PaxHeader/tests 000755 777777 777777 00000000210 11456036475 020253 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311435
18 SCHILY.nlink=7
tilecache-2.11/tests/ 000755 473017214730172100000000000 11456036475 016521 5 ustar 00christos christos 000000 000000 tilecache-2.11/PaxHeader/TileCache 000755 777777 777777 00000000257 11456036475 020745 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142716
38 LIBARCHIVE.creationtime=1287142716
24 SCHILY.dev=234881029
22 SCHILY.ino=3311397
19 SCHILY.nlink=12
tilecache-2.11/TileCache/ 000755 473017214730172100000000000 11456036475 017200 5 ustar 00christos christos 000000 000000 tilecache-2.11/PaxHeader/tilecache.cfg 000644 777777 777777 00000000210 11065024774 021560 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142716
20 atime=1287142716
24 SCHILY.dev=234881029
22 SCHILY.ino=3311396
18 SCHILY.nlink=1
tilecache-2.11/tilecache.cfg 000644 473017214730172100000006516 11065024774 017764 0 ustar 00christos christos 000000 000000 # Configuration for MC TileCache
# TileCache can load Layers or Caches from anywhere in sys.path. If you
# prefer to load from somewhere which is *not* on sys.path, you can use
# the path configuration paramter to set a comma-seperated list of
# filesystem paths which you want prepended to sys.path.
#[tilecache_options]
#path=/home/you
# Some TileCache options are controlled by metadata. One example is the
# crossdomain_sites option, which allows you to add sites which are then
# included in a crossdomain.xml file served from the root of the TileCache
#[metadata]
#crossdomain_sites=openstreetmap.org,openaerialmap.org
# [cache] section examples: (mandatory!)
#
# Disk:
# [cache]
# type=Disk (works out of the box)
# base=
#
# Memcached:
# [cache]
# type=Memcached (you'll need memcache.py and memcached running!)
# servers=192.168.1.1:11211
#
# Amazon S3:
# [cache]
# type=AWSS3
# access_key=your_access_key
# secret_access_key=your_secret_access_key
[cache]
type=Disk
base=/tmp/tilecache
# [layername] -- all other sections are named layers
#
# type={MapServerLayer,WMSLayer}
# *** if you want to use MapServerLayer, you *must* have Python mapscript
# installed and available ***
#
# mapfile=
# url=
# layers=[,,,...]
# *** optional iff layername if what
# your data source calls the layer **
# extension={png,jpeg,gif} *** defaults to "png" ***
# size=256,256 *** defaults to 256x256 ***
# bbox=-180.0,-90.0,180.0,90.0 *** defaults to world in lon/lat ***
# srs=EPSG:4326 *** defaults to EPSG:4326 ***
# levels=20 *** defaults to 20 zoom levels ***
# resolutions=0.1,0.05,0.025,... *** defaults to global profile ***
# metaTile=true *** metatiling off by default
# requires python-imaging ***
# metaSize=5,5 *** size of metatile in tiles
# defaults to 5 x 5 ***
# metaBuffer=10 *** size of metatile buffer in px ***
# mime_type=image/png *** by default, the mime type is image/extension ***
# *** but you may want to set extension=png8 for ***
# *** GeoServer WMS, and this lets you set the ***
# *** mime_type seperately. ***
# The following is a demonstration of a layer which would be generated
# according to the 'Google projection'. This uses the standard values for
# a spherical mercator projection for maxextent, maxresolution, units
# and srs.
# [google-tiles]
# type=WMS
# url=http://localhost/cgi-bin/mapserv?map=/mapdata/world.map
# layers=world
# spherical_mercator=true
# Standard MapServer layer configuration.
# [vmap0]
# type=MapServer
# layers=vmap0
# mapfile=/var/www/vmap0.map
# Rendering OpenStreetMap data with Mapnik; should use metaTiling to
# avoid labels across tile boundaries
# [osm]
# type=Mapnik
# mapfile=/home/user/osm-mapnik/osm.xml
# spherical_mercator=true
# tms_type=google
# metatile=yes
[basic]
type=WMS
url=http://labs.metacarta.com/wms/vmap0
extension=png
tilecache-2.11/PaxHeader/tilecache.cgi 000755 777777 777777 00000000210 10600505762 021561 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311441
18 SCHILY.nlink=1
tilecache-2.11/tilecache.cgi 000755 473017214730172100000000236 10600505762 017756 0 ustar 00christos christos 000000 000000 #!/usr/bin/env python
from TileCache import Service, cgiHandler, cfgfiles
if __name__ == '__main__':
svc = Service.load(*cfgfiles)
cgiHandler(svc)
tilecache-2.11/PaxHeader/tilecache.fcgi 000644 777777 777777 00000000210 10571173007 021724 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142718
20 atime=1287142718
24 SCHILY.dev=234881029
22 SCHILY.ino=3311462
18 SCHILY.nlink=1
tilecache-2.11/tilecache.fcgi 000644 473017214730172100000000244 10571173007 020120 0 ustar 00christos christos 000000 000000 #!/usr/bin/python
from TileCache.Service import wsgiApp
if __name__ == '__main__':
from flup.server.fcgi_fork import WSGIServer
WSGIServer(wsgiApp).run()
tilecache-2.11/PaxHeader/tilecache_clean.py 000755 777777 777777 00000000210 11456032102 022602 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142718
20 atime=1287142718
24 SCHILY.dev=234881029
22 SCHILY.ino=3311465
18 SCHILY.nlink=1
tilecache-2.11/tilecache_clean.py 000755 473017214730172100000005360 11456032102 021002 0 ustar 00christos christos 000000 000000 #!/usr/bin/env python
# BSD Licensed, Copyright (c) 2006-2010 TileCache Contributors
"""This is intended to be run as a command line tool. Use --help to determine
arguments to this program. It is a tool to keep a certain directory
to a maximum size by removing least recently accessed files from the
directory."""
import sys, os, heapq, time
from optparse import OptionParser
MAX_HEAP_SIZE = 1000000
MAX_CACHE_SIZE = 500 # MB
def walk_disk_cache (rootdir, max_entries):
"""Walk a directory structure, building a heap of up to max_entries."""
heap = []
cache_size = 0
start = time.time()
for root, dirs, files in os.walk(rootdir):
for file in files:
path = os.path.join(root, file)
stat = os.stat(path)
size = stat.st_size
if hasattr(stat, 'st_blocks'):
size = stat.st_blocks * stat.st_blksize
# strip off rootdir to keep RAM use down
path = path[len(rootdir):]
heapq.heappush(heap, (stat.st_atime, size, path))
cache_size += size
del heap[max_entries:]
return heap, cache_size
def clean_disk_cache (rootdir, max_size, max_entries):
"""Remove files from directory until its size is less than max_size (which
is megabytes). Up to max_entries will be removed per-run."""
heap, cache_size = walk_disk_cache(rootdir, max_entries)
max_size <<= 20 # megabytes
print "Cache entries found: %d" % len(heap)
removed_files = 0
while heap and cache_size > max_size:
atime, size, path = heapq.heappop(heap)
cache_size -= size
path = rootdir + path
try:
os.unlink(path)
removed_files += 1
except OSError, e:
print >>sys.stderr, "Error removing tile %s: %s" % (path, e)
print "Removed %d files." % removed_files
if __name__ == "__main__":
usage = "usage: %prog [options] "
parser = OptionParser(usage=usage, version="%prog 1.0")
parser.add_option("-s", "--size", action="store", type="int",
dest="size", default = MAX_CACHE_SIZE,
help="Maximum cache size, in megabytes.")
parser.add_option("-e", "--entries", action="store", type="int",
dest="entries", default=MAX_HEAP_SIZE,
help="""Maximum cache entries. This limits the
amount of memory that will be used to store
information about tiles to remove.""")
(options, args) = parser.parse_args()
if not len(args):
parser.error("Missing required cache_location argument.")
clean_disk_cache(args[0], options.size, options.entries)
tilecache-2.11/PaxHeader/tilecache_http_server.py 000755 777777 777777 00000000210 10767604622 024105 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142718
20 atime=1287142718
24 SCHILY.dev=234881029
22 SCHILY.ino=3311467
18 SCHILY.nlink=1
tilecache-2.11/tilecache_http_server.py 000755 473017214730172100000002113 10767604622 022276 0 ustar 00christos christos 000000 000000 #!/usr/bin/python
from TileCache.Service import wsgiApp
from optparse import OptionParser
def run(port=8080, threading=False, config=None):
from wsgiref import simple_server
if threading:
from SocketServer import ThreadingMixIn
class myServer(ThreadingMixIn, simple_server.WSGIServer):
pass
httpd = myServer(('',port), simple_server.WSGIRequestHandler,)
else:
httpd = simple_server.WSGIServer(('',port), simple_server.WSGIRequestHandler,)
httpd.set_app(wsgiApp)
try:
print "Listening on port %s" % port
httpd.serve_forever()
except KeyboardInterrupt:
print "Shutting down."
if __name__ == '__main__':
parser = OptionParser()
parser.add_option("-p", "--port", help="port to run webserver on. Default is 8080", dest="port", action='store', type="int", default=8080)
parser.add_option("-t", "--threading", help="threading http server. default is false", dest="threading", action='store_true', default=False)
(options, args) = parser.parse_args()
run(options.port, options.threading)
tilecache-2.11/PaxHeader/tilecache_install_config.py 000644 777777 777777 00000000210 10733230256 024517 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311442
18 SCHILY.nlink=1
tilecache-2.11/tilecache_install_config.py 000644 473017214730172100000002275 10733230256 022721 0 ustar 00christos christos 000000 000000 #!/usr/bin/python
"""Script to install a TileCache config from an egg installation."""
import sys
from optparse import OptionParser
def install(dest):
try:
f = open(dest, "w")
except IOError, E:
print "Unable to open destination file %s. Perhaps you need permission to write there?\n(Error was: %s)" % (dest, E)
sys.exit(1)
try:
import pkg_resources
filename = pkg_resources.resource_filename("TileCache", "tilecache.cfg")
cfg = open(filename, "r")
except Exception, E:
print "Unable to open source file.\n(Error was: %s)" % (E)
sys.exit(1)
f.write(cfg.read())
f.close()
cfg.close()
print "Successfully copied file %s to %s." % (filename, dest)
if __name__ == "__main__":
parser = OptionParser(usage="""%prog [options]
This script is a helper script designed to install the default TileCache
configuration when TileCache is installed from an egg.""")
parser.add_option('-d', '--dest', dest="dest", help="install to FILE. Default is /etc/tilecache.cfg", default="/etc/tilecache.cfg", metavar="FILE")
(options, args) = parser.parse_args()
install(options.dest)
tilecache-2.11/PaxHeader/tilecache_seed.py 000755 777777 777777 00000000210 11456032102 022440 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142718
20 atime=1287142718
24 SCHILY.dev=234881029
22 SCHILY.ino=3311463
18 SCHILY.nlink=1
tilecache-2.11/tilecache_seed.py 000755 473017214730172100000000376 11456032102 020642 0 ustar 00christos christos 000000 000000 #!/usr/bin/env python
# BSD Licensed, Copyright (c) 2006-2010 TileCache Contributors
"""This is intended to be run as a command line tool. See the accompanying
README file or man page for details."""
import TileCache.Client
TileCache.Client.main()
tilecache-2.11/TileCache/PaxHeader/__init__.py 000644 777777 777777 00000000210 11456032102 023074 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311430
18 SCHILY.nlink=1
tilecache-2.11/TileCache/__init__.py 000644 473017214730172100000000222 11456032102 021264 0 ustar 00christos christos 000000 000000 # BSD Licensed, Copyright (c) 2006-2010 TileCache Contributors
from Cache import *
from Layer import *
from Client import *
from Service import *
tilecache-2.11/TileCache/PaxHeader/Cache.py 000644 777777 777777 00000000210 11456032102 022340 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311432
18 SCHILY.nlink=1
tilecache-2.11/TileCache/Cache.py 000644 473017214730172100000003062 11456032102 020535 0 ustar 00christos christos 000000 000000 # BSD Licensed, Copyright (c) 2006-2010 TileCache Contributors
import os, sys, time
from warnings import warn
class Cache (object):
def __init__ (self, timeout = 30.0, stale_interval = 300.0, readonly = False, expire = False, sendfile = False, **kwargs):
self.stale = float(stale_interval)
self.timeout = float(timeout)
self.readonly = readonly
self.expire = expire
self.sendfile = sendfile and sendfile.lower() in ["yes", "y", "t", "true"]
if expire != False:
self.expire = long(expire)
def lock (self, tile, blocking = True):
start_time = time.time()
result = self.attemptLock(tile)
if result:
return True
elif not blocking:
return False
while result is not True:
if time.time() - start_time > self.timeout:
raise Exception("You appear to have a stuck lock. You may wish to remove the lock named:\n%s" % self.getLockName(tile))
time.sleep(0.25)
result = self.attemptLock(tile)
return True
def getLockName (self, tile):
return self.getKey(tile) + ".lck"
def getKey (self, tile):
raise NotImplementedError()
def attemptLock (self, tile):
raise NotImplementedError()
def unlock (self, tile):
raise NotImplementedError()
def get (self, tile):
raise NotImplementedError()
def set (self, tile, data):
raise NotImplementedError()
def delete(self, tile):
raise NotImplementedError()
tilecache-2.11/TileCache/PaxHeader/Caches 000755 777777 777777 00000000211 11456036475 022121 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311421
19 SCHILY.nlink=10
tilecache-2.11/TileCache/Caches/ 000755 473017214730172100000000000 11456036475 020366 5 ustar 00christos christos 000000 000000 tilecache-2.11/TileCache/PaxHeader/Client.py 000644 777777 777777 00000000210 11456032102 022553 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311420
18 SCHILY.nlink=1
tilecache-2.11/TileCache/Client.py 000644 473017214730172100000017271 11456032102 020757 0 ustar 00christos christos 000000 000000 #!/usr/bin/env python
# BSD Licensed, Copyright (c) 2006-2010 TileCache Contributors
import sys, urllib, urllib2, time, os, math
import time
import httplib
try:
from optparse import OptionParser
except ImportError:
OptionParser = False
# setting this to True will exchange more useful error messages
# for privacy, hiding URLs and error messages.
HIDE_ALL = False
class WMS (object):
fields = ("bbox", "srs", "width", "height", "format", "layers", "styles")
defaultParams = {'version': '1.1.1', 'request': 'GetMap', 'service': 'WMS'}
__slots__ = ("base", "params", "client", "data", "response")
def __init__ (self, base, params, user=None, password=None):
self.base = base
if self.base[-1] not in "?&":
if "?" in self.base:
self.base += "&"
else:
self.base += "?"
self.params = {}
if user is not None and password is not None:
x = urllib2.HTTPPasswordMgrWithDefaultRealm()
x.add_password(None, base, user, password)
self.client = urllib2.build_opener()
auth = urllib2.HTTPBasicAuthHandler(x)
self.client = urllib2.build_opener(auth)
else:
self.client = urllib2.build_opener()
for key, val in self.defaultParams.items():
if self.base.lower().rfind("%s=" % key.lower()) == -1:
self.params[key] = val
for key in self.fields:
if params.has_key(key):
self.params[key] = params[key]
elif self.base.lower().rfind("%s=" % key.lower()) == -1:
self.params[key] = ""
def url (self):
return self.base + urllib.urlencode(self.params)
def fetch (self):
urlrequest = urllib2.Request(self.url())
# urlrequest.add_header("User-Agent",
# "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)" )
response = None
while response is None:
try:
response = self.client.open(urlrequest)
data = response.read()
# check to make sure that we have an image...
msg = response.info()
if msg.has_key("Content-Type"):
ctype = msg['Content-Type']
if ctype[:5].lower() != 'image':
if HIDE_ALL:
raise Exception("Did not get image data back. (Adjust HIDE_ALL for more detail.)")
else:
raise Exception("Did not get image data back. \nURL: %s\nContent-Type Header: %s\nResponse: \n%s" % (self.url(), ctype, data))
except httplib.BadStatusLine:
response = None # try again
return data, response
def setBBox (self, box):
self.params["bbox"] = ",".join(map(str, box))
def seed (svc, layer, levels = (0, 5), bbox = None, padding = 0, force = False, reverse = False, delay = 0 ):
from Layer import Tile
try:
padding = int(padding)
except:
raise Exception('Your padding parameter is %s, but should be an integer' % padding)
if not bbox: bbox = layer.bbox
start = time.time()
total = 0
for z in range(*levels):
bottomleft = layer.getClosestCell(z, bbox[0:2])
topright = layer.getClosestCell(z, bbox[2:4])
# Why Are we printing to sys.stderr??? It's not an error.
# This causes a termination if run from cron or in background if shell is terminated
#print >>sys.stderr, "###### %s, %s" % (bottomleft, topright)
print "###### %s, %s" % (bottomleft, topright)
zcount = 0
metaSize = layer.getMetaSize(z)
ztiles = int(math.ceil(float(topright[1] - bottomleft[1]) / metaSize[0]) * math.ceil(float(topright[0] - bottomleft[0]) / metaSize[1]))
if reverse:
startX = topright[0] + metaSize[0] + (1 * padding)
endX = bottomleft[0] - (1 * padding)
stepX = -metaSize[0]
startY = topright[1] + metaSize[1] + (1 * padding)
endY = bottomleft[1] - (1 * padding)
stepY = -metaSize[1]
else:
startX = bottomleft[0] - (1 * padding)
endX = topright[0] + metaSize[0] + (1 * padding)
stepX = metaSize[0]
startY = bottomleft[1] - (1 * padding)
endY = topright[1] + metaSize[1] + (1 * padding)
stepY = metaSize[1]
for y in range(startY, endY, stepY):
for x in range(startX, endX, stepX):
tileStart = time.time()
tile = Tile(layer,x,y,z)
bounds = tile.bounds()
svc.renderTile(tile,force=force)
total += 1
zcount += 1
box = "(%.4f %.4f %.4f %.4f)" % bounds
print "%02d (%06d, %06d) = %s [%.4fs : %.3f/s] %s/%s" \
% (z,x,y, box, time.time() - tileStart, total / (time.time() - start + .0001), zcount, ztiles)
if delay:
time.sleep(delay)
def main ():
if not OptionParser:
raise Exception("TileCache seeding requires optparse/OptionParser. Your Python may be too old.\nSend email to the mailing list \n(http://openlayers.org/mailman/listinfo/tilecache) about this problem for help.")
usage = "usage: %prog []"
parser = OptionParser(usage=usage, version="%prog $Id: Client.py 406 2010-10-15 11:00:18Z crschmidt $")
parser.add_option("-f","--force", action="store_true", dest="force", default = False,
help="force recreation of tiles even if they are already in cache")
parser.add_option("-b","--bbox",action="store", type="string", dest="bbox", default = None,
help="restrict to specified bounding box")
parser.add_option("-c", "--config", action="store", type="string", dest="tilecacheconfig",
default=None, help="path to configuration file")
parser.add_option("-d","--delay",action="store", type="int", dest="delay", default = 0,
help="Delay time between requests.")
parser.add_option("-p","--padding",action="store", type="int", dest="padding", default = 0,
help="extra margin tiles to seed around target area. Defaults to 0 "+
"(some edge tiles might be missing). A value of 1 ensures all tiles "+
"will be created, but some tiles may be wholly outside your bbox")
parser.add_option("-r","--reverse", action="store_true", dest="reverse", default = False,
help="Reverse order of seeding tiles")
(options, args) = parser.parse_args()
if len(args)>3:
parser.error("Incorrect number of arguments. bbox and padding are now options (-b and -p)")
from Service import Service, cfgfiles
from Layer import Layer
cfgs = cfgfiles
if options.tilecacheconfig:
configFile = options.tilecacheconfig
print "Config file set to %s" % (configFile)
cfgs = cfgs + (configFile,)
svc = Service.load(*cfgs)
layer = svc.layers[args[0]]
if options.bbox:
bboxlist = map(float,options.bbox.split(","))
else:
bboxlist=None
if len(args)>1:
seed(svc, layer, map(int, args[1:3]), bboxlist , padding=options.padding, force = options.force, reverse = options.reverse, delay=options.delay)
else:
for line in sys.stdin.readlines():
lat, lon, delta = map(float, line.split(","))
bbox = (lon - delta, lat - delta, lon + delta, lat + delta)
print "===> %s <===" % (bbox,)
seed(svc, layer, (5, 17), bbox , force = options.force )
if __name__ == '__main__':
main()
tilecache-2.11/TileCache/PaxHeader/Layer.py 000644 777777 777777 00000000210 11456032102 022411 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142716
20 atime=1287142716
24 SCHILY.dev=234881029
22 SCHILY.ino=3311407
18 SCHILY.nlink=1
tilecache-2.11/TileCache/Layer.py 000644 473017214730172100000041625 11456032102 020615 0 ustar 00christos christos 000000 000000 # BSD Licensed, Copyright (c) 2006-2010 TileCache Contributors
import os, sys
from warnings import warn
from Client import WMS
from Service import TileCacheException
DEBUG = True
class Tile (object):
"""
>>> l = Layer("name", maxresolution=0.019914, size="256,256")
>>> t = Tile(l, 18, 20, 0)
"""
__slots__ = ( "layer", "x", "y", "z", "data" )
def __init__ (self, layer, x, y, z):
"""
>>> l = Layer("name", maxresolution=0.019914, size="256,256")
>>> t = Tile(l, 18, 20, 0)
>>> t.x
18
>>> t.y
20
>>> t.z
0
>>> print t.data
None
"""
self.layer = layer
self.x = x
self.y = y
self.z = z
self.data = None
def size (self):
"""
>>> l = Layer("name", maxresolution=0.019914, size="256,256")
>>> t = Tile(l, 18, 20, 0)
>>> t.size()
[256, 256]
"""
return self.layer.size
def bounds (self):
"""
>>> l = Layer("name", maxresolution=0.019914)
>>> t = Tile(l, 18, 20, 0)
>>> t.bounds()
(-88.236288000000002, 11.959680000000006, -83.138303999999991, 17.057664000000003)
"""
res = self.layer.resolutions[self.z]
minx = self.layer.bbox[0] + (res * self.x * self.layer.size[0])
miny = self.layer.bbox[1] + (res * self.y * self.layer.size[1])
maxx = self.layer.bbox[0] + (res * (self.x + 1) * self.layer.size[0])
maxy = self.layer.bbox[1] + (res * (self.y + 1) * self.layer.size[1])
return (minx, miny, maxx, maxy)
def bbox (self):
"""
>>> l = Layer("name", maxresolution=0.019914)
>>> t = Tile(l, 18, 20, 0)
>>> t.bbox()
'-88.236288,11.95968,-83.138304,17.057664'
"""
return ",".join(map(str, self.bounds()))
class MetaTile (Tile):
def actualSize (self):
"""
>>> l = MetaLayer("name")
>>> t = MetaTile(l, 0,0,0)
>>> t.actualSize()
(256, 256)
"""
metaCols, metaRows = self.layer.getMetaSize(self.z)
return ( self.layer.size[0] * metaCols,
self.layer.size[1] * metaRows )
def size (self):
actual = self.actualSize()
return ( actual[0] + self.layer.metaBuffer[0] * 2,
actual[1] + self.layer.metaBuffer[1] * 2 )
def bounds (self):
tilesize = self.actualSize()
res = self.layer.resolutions[self.z]
buffer = (res * self.layer.metaBuffer[0], res * self.layer.metaBuffer[1])
metaWidth = res * tilesize[0]
metaHeight = res * tilesize[1]
minx = self.layer.bbox[0] + self.x * metaWidth - buffer[0]
miny = self.layer.bbox[1] + self.y * metaHeight - buffer[1]
maxx = minx + metaWidth + 2 * buffer[0]
maxy = miny + metaHeight + 2 * buffer[1]
return (minx, miny, maxx, maxy)
class Layer (object):
__slots__ = ( "name", "layers", "bbox", "data_extent",
"size", "resolutions", "extension", "srs",
"cache", "debug", "description",
"watermarkimage", "watermarkopacity",
"extent_type", "tms_type", "units", "mime_type",
"paletted",
"spherical_mercator", "metadata")
config_properties = [
{'name':'spherical_mercator', 'description':'Layer is in spherical mercator. (Overrides bbox, maxresolution, SRS, Units)', 'type': 'boolean'},
{'name':'layers', 'description': 'Comma seperated list of layers associated with this layer.'},
{'name':'extension', 'description':'File type extension', 'default':'png'},
{'name':'bbox', 'description':'Bounding box of the layer grid', 'default':'-180,-90,180,90'},
{'name':'srs', 'description':'Spatial Reference System for the layer', 'default':'EPSG:4326'},
{'name':'data_extent', 'description':'Bounding box of the layer data. (Same SRS as the layer grid.)', 'default':"", 'type': 'map'},
]
def __init__ (self, name, layers = None, bbox = (-180, -90, 180, 90),
data_extent = None,
srs = "EPSG:4326", description = "", maxresolution = None,
size = (256, 256), levels = 20, resolutions = None,
extension = "png", mime_type = None, cache = None, debug = True,
watermarkimage = None, watermarkopacity = 0.2,
spherical_mercator = False,
extent_type = "strict", units = "degrees", tms_type = "", **kwargs ):
"""Take in parameters, usually from a config file, and create a Layer.
>>> l = Layer("Name", bbox="-12,17,22,36", debug="no")
>>> l.bbox
[-12.0, 17.0, 22.0, 36.0]
>>> l.debug
False
>>> l = Layer("name", spherical_mercator="yes")
>>> round(l.resolutions[0])
156543.0
"""
self.name = name
self.description = description
self.layers = layers or name
self.paletted = False
self.spherical_mercator = spherical_mercator and spherical_mercator.lower() in ["yes", "y", "t", "true"]
if self.spherical_mercator:
bbox = "-20037508.34,-20037508.34,20037508.34,20037508.34"
maxresolution = "156543.0339"
if srs == "EPSG:4326":
srs = "EPSG:900913"
units = "meters"
if isinstance(bbox, str):
bbox = map(float, bbox.split(","))
self.bbox = bbox
if isinstance(data_extent, str):
data_extent = map(float, data_extent.split(","))
self.data_extent = data_extent or bbox
if isinstance(size, str):
size = map(int, size.split(","))
self.size = size
self.units = units
self.srs = srs
if extension.lower() == 'jpg':
extension = 'jpeg' # MIME
elif extension.lower() == 'png256':
extension = 'png'
self.paletted = True
self.extension = extension.lower()
self.mime_type = mime_type or self.format()
if isinstance(debug, str):
debug = debug.lower() not in ("false", "off", "no", "0")
self.debug = debug
self.cache = cache
self.extent_type = extent_type
self.tms_type = tms_type
if resolutions:
if isinstance(resolutions, str):
resolutions = map(float,resolutions.split(","))
self.resolutions = resolutions
else:
maxRes = None
if not maxresolution:
width = bbox[2] - bbox[0]
height = bbox[3] - bbox[1]
if width >= height:
aspect = int( float(width) / height + .5 ) # round up
maxRes = float(width) / (size[0] * aspect)
else:
aspect = int( float(height) / width + .5 ) # round up
maxRes = float(height) / (size[1] * aspect)
else:
maxRes = float(maxresolution)
self.resolutions = [maxRes / 2 ** i for i in range(int(levels))]
self.watermarkimage = watermarkimage
self.watermarkopacity = float(watermarkopacity)
self.metadata = {}
prefix_len = len("metadata_")
for key in kwargs:
if key.startswith("metadata_"):
self.metadata[key[prefix_len:]] = kwargs[key]
def getResolution (self, (minx, miny, maxx, maxy)):
"""
>>> l = Layer("name")
>>> l.getResolution((-180,-90,0,90))
0.703125
"""
return max( float(maxx - minx) / self.size[0],
float(maxy - miny) / self.size[1] )
def getClosestLevel (self, res, size = [256, 256]):
diff = sys.maxint
z = None
for i in range(len(self.resolutions)):
if diff > abs( self.resolutions[i] - res ):
diff = abs( self.resolutions[i] - res )
z = i
return z
def getLevel (self, res, size = [256, 256]):
"""
>>> l = Layer("name")
>>> l.getLevel(.703125)
0
"""
max_diff = res / max(size[0], size[1])
z = None
for i in range(len(self.resolutions)):
if abs( self.resolutions[i] - res ) < max_diff:
res = self.resolutions[i]
z = i
break
if z is None:
raise TileCacheException("can't find resolution index for %f. Available resolutions are: \n%s" % (res, self.resolutions))
return z
def getCell (self, (minx, miny, maxx, maxy), exact = True):
"""
Returns x, y, z
>>> l = Layer("name")
>>> l.bbox
(-180, -90, 180, 90)
>>> l.resolutions[0]
0.703125
>>> l.getCell((-180.,-90.,0.,90.))
(0, 0, 0)
>>> l.getCell((-45.,-45.,0.,0.))
(3, 1, 2)
"""
res = self.getResolution((minx, miny, maxx, maxy))
x = y = None
if exact:
z = self.getLevel(res, self.size)
else:
z = self.getClosestLevel(res, self.size)
res = self.resolutions[z]
if exact and self.extent_type == "strict" and not self.contains((minx, miny), res):
raise TileCacheException("Lower left corner (%f, %f) is outside layer bounds %s. \nTo remove this condition, set extent_type=loose in your configuration."
% (minx, miny, self.bbox))
return None
x0 = (minx - self.bbox[0]) / (res * self.size[0])
y0 = (miny - self.bbox[1]) / (res * self.size[1])
x = int(x0)
y = int(y0)
tilex = ((x * res * self.size[0]) + self.bbox[0])
tiley = ((y * res * self.size[1]) + self.bbox[1])
if exact:
if (abs(minx - tilex) / res > 1):
raise TileCacheException("Current x value %f is too far from tile corner x %f" % (minx, tilex))
if (abs(miny - tiley) / res > 1):
raise TileCacheException("Current y value %f is too far from tile corner y %f" % (miny, tiley))
return (x, y, z)
def getClosestCell (self, z, (minx, miny)):
"""
>>> l = Layer("name")
>>> l.getClosestCell(2, (84, 17))
(6, 2, 2)
"""
res = self.resolutions[z]
maxx = minx + self.size[0] * res
maxy = miny + self.size[1] * res
return self.getCell((minx, miny, maxx, maxy), False)
def getTile (self, bbox):
"""
>>> l = Layer("name")
>>> l.getTile((-180,-90,0,90)).bbox()
'-180.0,-90.0,0.0,90.0'
"""
coord = self.getCell(bbox)
if not coord: return None
return Tile(self, *coord)
def contains (self, (x, y), res = 0):
"""
>>> l = Layer("name")
>>> l.contains((0,0))
True
>>> l.contains((185, 94))
False
"""
diff_x1 = abs(x - self.bbox[0])
diff_x2 = abs(x - self.bbox[2])
diff_y1 = abs(y - self.bbox[1])
diff_y2 = abs(y - self.bbox[3])
return (x >= self.bbox[0] or diff_x1 < res) and (x <= self.bbox[2] or diff_x2 < res) \
and (y >= self.bbox[1] or diff_y1 < res) and (y <= self.bbox[3] or diff_y2 < res)
def grid (self, z):
"""
Returns size of grid at a particular zoom level
>>> l = Layer("name")
>>> l.grid(3)
(16.0, 8.0)
"""
width = (self.bbox[2] - self.bbox[0]) / (self.resolutions[z] * self.size[0])
height = (self.bbox[3] - self.bbox[1]) / (self.resolutions[z] * self.size[1])
return (width, height)
def format (self):
"""
>>> l = Layer("name")
>>> l.format()
'image/png'
"""
return "image/" + self.extension
def renderTile (self, tile):
# To be implemented by subclasses
pass
def render (self, tile, **kwargs):
return self.renderTile(tile)
class MetaLayer (Layer):
__slots__ = ('metaTile', 'metaSize', 'metaBuffer')
config_properties = Layer.config_properties + [
{'name':'name', 'description': 'Name of Layer'},
{'name':'metaTile', 'description': 'Should metatiling be used on this layer?', 'default': 'false', 'type':'boolean'},
{'name': 'metaSize', 'description': 'Comma seperated-pair of numbers, defininig the tiles included in a single size', 'default': "5,5"},
{'name': 'metaBuffer', 'description': 'Number of pixels outside the metatile to include in the render request.'}
]
def __init__ (self, name, metatile = "", metasize = (5,5),
metabuffer = (10,10), **kwargs):
Layer.__init__(self, name, **kwargs)
self.metaTile = metatile.lower() in ("true", "yes", "1")
if isinstance(metasize, str):
metasize = map(int,metasize.split(","))
if isinstance(metabuffer, str):
metabuffer = map(int, metabuffer.split(","))
if len(metabuffer) == 1:
metabuffer = (metabuffer[0], metabuffer[0])
self.metaSize = metasize
self.metaBuffer = metabuffer
def getMetaSize (self, z):
if not self.metaTile: return (1,1)
maxcol, maxrow = self.grid(z)
return ( min(self.metaSize[0], int(maxcol + 1)),
min(self.metaSize[1], int(maxrow + 1)) )
def getMetaTile (self, tile):
x = int(tile.x / self.metaSize[0])
y = int(tile.y / self.metaSize[1])
return MetaTile(self, x, y, tile.z)
def renderMetaTile (self, metatile, tile):
import StringIO, Image
data = self.renderTile(metatile)
image = Image.open( StringIO.StringIO(data) )
metaCols, metaRows = self.getMetaSize(metatile.z)
metaHeight = metaRows * self.size[1] + 2 * self.metaBuffer[1]
for i in range(metaCols):
for j in range(metaRows):
minx = i * self.size[0] + self.metaBuffer[0]
maxx = minx + self.size[0]
### this next calculation is because image origin is (top,left)
maxy = metaHeight - (j * self.size[1] + self.metaBuffer[1])
miny = maxy - self.size[1]
subimage = image.crop((minx, miny, maxx, maxy))
buffer = StringIO.StringIO()
if image.info.has_key('transparency'):
subimage.save(buffer, self.extension, transparency=image.info['transparency'])
else:
subimage.save(buffer, self.extension)
buffer.seek(0)
subdata = buffer.read()
x = metatile.x * self.metaSize[0] + i
y = metatile.y * self.metaSize[1] + j
subtile = Tile( self, x, y, metatile.z )
if self.watermarkimage:
subdata = self.watermark(subdata)
self.cache.set( subtile, subdata )
if x == tile.x and y == tile.y:
tile.data = subdata
return tile.data
def render (self, tile, force=False):
if self.metaTile:
metatile = self.getMetaTile(tile)
try:
self.cache.lock(metatile)
image = None
if not force:
image = self.cache.get(tile)
if not image:
image = self.renderMetaTile(metatile, tile)
finally:
self.cache.unlock(metatile)
return image
else:
if self.watermarkimage:
return self.watermark(self.renderTile(tile))
else:
return self.renderTile(tile)
def watermark (self, img):
import StringIO, Image, ImageEnhance
tileImage = Image.open( StringIO.StringIO(img) )
wmark = Image.open(self.watermarkimage)
assert self.watermarkopacity >= 0 and self.watermarkopacity <= 1
if wmark.mode != 'RGBA':
wmark = wmark.convert('RGBA')
else:
wmark = wmark.copy()
alpha = wmark.split()[3]
alpha = ImageEnhance.Brightness(alpha).enhance(self.watermarkopacity)
wmark.putalpha(alpha)
if tileImage.mode != 'RGBA':
tileImage = tileImage.convert('RGBA')
watermarkedImage = Image.new('RGBA', tileImage.size, (0,0,0,0))
watermarkedImage.paste(wmark, (0,0))
watermarkedImage = Image.composite(watermarkedImage, tileImage, watermarkedImage)
buffer = StringIO.StringIO()
if watermarkedImage.info.has_key('transparency'):
watermarkedImage.save(buffer, self.extension, transparency=compositeImage.info['transparency'])
else:
watermarkedImage.save(buffer, self.extension)
buffer.seek(0)
return buffer.read()
if __name__ == "__main__":
import doctest
doctest.testmod()
tilecache-2.11/TileCache/PaxHeader/Layers 000755 777777 777777 00000000210 11456036474 022170 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142716
20 atime=1287142716
24 SCHILY.dev=234881029
22 SCHILY.ino=3311398
18 SCHILY.nlink=9
tilecache-2.11/TileCache/Layers/ 000755 473017214730172100000000000 11456036474 020436 5 ustar 00christos christos 000000 000000 tilecache-2.11/TileCache/PaxHeader/Peer 000755 777777 777777 00000000210 11456036475 021625 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311433
18 SCHILY.nlink=3
tilecache-2.11/TileCache/Peer/ 000755 473017214730172100000000000 11456036475 020073 5 ustar 00christos christos 000000 000000 tilecache-2.11/TileCache/PaxHeader/Service.py 000755 777777 777777 00000000210 11456032102 022740 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311431
18 SCHILY.nlink=1
tilecache-2.11/TileCache/Service.py 000755 473017214730172100000041607 11456032102 021144 0 ustar 00christos christos 000000 000000 #!/usr/bin/python
# BSD Licensed, Copyright (c) 2006-2010 TileCache Contributors
class TileCacheException(Exception): pass
import sys, cgi, time, os, traceback, email, ConfigParser
import Cache, Caches
import Layer, Layers
# Windows doesn't always do the 'working directory' check correctly.
if sys.platform == 'win32':
workingdir = os.path.abspath(os.path.join(os.getcwd(), os.path.dirname(sys.argv[0])))
cfgfiles = (os.path.join(workingdir, "tilecache.cfg"), os.path.join(workingdir,"..","tilecache.cfg"))
else:
cfgfiles = ("/etc/tilecache.cfg", os.path.join("..", "tilecache.cfg"), "tilecache.cfg")
class Capabilities (object):
def __init__ (self, format, data):
self.format = format
self.data = data
class Request (object):
def __init__ (self, service):
self.service = service
def getLayer(self, layername):
try:
return self.service.layers[layername]
except:
raise TileCacheException("The requested layer (%s) does not exist. Available layers are: \n * %s" % (layername, "\n * ".join(self.service.layers.keys())))
def import_module(name):
"""Helper module to import any module based on a name, and return the module."""
mod = __import__(name)
components = name.split('.')
for comp in components[1:]:
mod = getattr(mod, comp)
return mod
class Service (object):
__slots__ = ("layers", "cache", "metadata", "tilecache_options", "config", "files")
def __init__ (self, cache, layers, metadata = {}):
self.cache = cache
self.layers = layers
self.metadata = metadata
def _loadFromSection (cls, config, section, module, **objargs):
type = config.get(section, "type")
for opt in config.options(section):
if opt not in ["type", "module"]:
objargs[opt] = config.get(section, opt)
object_module = None
if config.has_option(section, "module"):
object_module = import_module(config.get(section, "module"))
else:
if module is Layer:
type = type.replace("Layer", "")
object_module = import_module("TileCache.Layers.%s" % type)
else:
type = type.replace("Cache", "")
object_module = import_module("TileCache.Caches.%s" % type)
if object_module == None:
raise TileCacheException("Attempt to load %s failed." % type)
section_object = getattr(object_module, type)
if module is Layer:
return section_object(section, **objargs)
else:
return section_object(**objargs)
loadFromSection = classmethod(_loadFromSection)
def _load (cls, *files):
cache = None
metadata = {}
layers = {}
config = None
try:
config = ConfigParser.ConfigParser()
config.read(files)
if config.has_section("metadata"):
for key in config.options("metadata"):
metadata[key] = config.get("metadata", key)
if config.has_section("tilecache_options"):
if 'path' in config.options("tilecache_options"):
for path in config.get("tilecache_options", "path").split(","):
sys.path.insert(0, path)
cache = cls.loadFromSection(config, "cache", Cache)
layers = {}
for section in config.sections():
if section in cls.__slots__: continue
layers[section] = cls.loadFromSection(
config, section, Layer,
cache = cache)
except Exception, E:
metadata['exception'] = E
metadata['traceback'] = "".join(traceback.format_tb(sys.exc_traceback))
service = cls(cache, layers, metadata)
service.files = files
service.config = config
return service
load = classmethod(_load)
def generate_crossdomain_xml(self):
"""Helper method for generating the XML content for a crossdomain.xml
file, to be used to allow remote sites to access this content."""
xml = ["""
"""]
if self.metadata.has_key('crossdomain_sites'):
sites = self.metadata['crossdomain_sites'].split(',')
for site in sites:
xml.append(' ' % site)
xml.append("")
return ('text/xml', "\n".join(xml))
def renderTile (self, tile, force = False):
from warnings import warn
start = time.time()
# do more cache checking here: SRS, width, height, layers
layer = tile.layer
image = None
if not force: image = self.cache.get(tile)
if not image:
data = layer.render(tile, force=force)
if (data): image = self.cache.set(tile, data)
else: raise Exception("Zero length data returned from layer.")
if layer.debug:
sys.stderr.write(
"Cache miss: %s, Tile: x: %s, y: %s, z: %s, time: %s\n" % (
tile.bbox(), tile.x, tile.y, tile.z, (time.time() - start)) )
else:
if layer.debug:
sys.stderr.write(
"Cache hit: %s, Tile: x: %s, y: %s, z: %s, time: %s, debug: %s\n" % (
tile.bbox(), tile.x, tile.y, tile.z, (time.time() - start), layer.debug) )
return (layer.mime_type, image)
def expireTile (self, tile):
bbox = tile.bounds()
layer = tile.layer
for z in range(len(layer.resolutions)):
bottomleft = layer.getClosestCell(z, bbox[0:2])
topright = layer.getClosestCell(z, bbox[2:4])
for y in range(bottomleft[1], topright[1] + 1):
for x in range(bottomleft[0], topright[0] + 1):
coverage = Layer.Tile(layer,x,y,z)
self.cache.delete(coverage)
def dispatchRequest (self, params, path_info="/", req_method="GET", host="http://example.com/"):
if self.metadata.has_key('exception'):
raise TileCacheException("%s\n%s" % (self.metadata['exception'], self.metadata['traceback']))
if path_info.find("crossdomain.xml") != -1:
return self.generate_crossdomain_xml()
if path_info.split(".")[-1] == "kml":
from TileCache.Services.KML import KML
return KML(self).parse(params, path_info, host)
if params.has_key("scale") or params.has_key("SCALE"):
from TileCache.Services.WMTS import WMTS
tile = WMTS(self).parse(params, path_info, host)
elif params.has_key("service") or params.has_key("SERVICE") or \
params.has_key("REQUEST") and params['REQUEST'] == "GetMap" or \
params.has_key("request") and params['request'] == "GetMap":
from TileCache.Services.WMS import WMS
tile = WMS(self).parse(params, path_info, host)
elif params.has_key("L") or params.has_key("l") or \
params.has_key("request") and params['request'] == "metadata":
from TileCache.Services.WorldWind import WorldWind
tile = WorldWind(self).parse(params, path_info, host)
elif params.has_key("interface"):
from TileCache.Services.TileService import TileService
tile = TileService(self).parse(params, path_info, host)
elif params.has_key("v") and \
(params['v'] == "mgm" or params['v'] == "mgmaps"):
from TileCache.Services.MGMaps import MGMaps
tile = MGMaps(self).parse(params, path_info, host)
elif params.has_key("tile"):
from TileCache.Services.VETMS import VETMS
tile = VETMS(self).parse(params, path_info, host)
elif params.has_key("format") and params['format'].lower() == "json":
from TileCache.Services.JSON import JSON
return JSON(self).parse(params, path_info, host)
else:
from TileCache.Services.TMS import TMS
tile = TMS(self).parse(params, path_info, host)
if isinstance(tile, Layer.Tile):
if req_method == 'DELETE':
self.expireTile(tile)
return ('text/plain', 'OK')
else:
return self.renderTile(tile, params.has_key('FORCE'))
elif isinstance(tile, list):
if req_method == 'DELETE':
[self.expireTile(t) for t in tile]
return ('text/plain', 'OK')
else:
try:
import PIL.Image as Image
except ImportError:
raise Exception("Combining multiple layers requires Python Imaging Library.")
try:
import cStringIO as StringIO
except ImportError:
import StringIO
result = None
for t in tile:
(format, data) = self.renderTile(t, params.has_key('FORCE'))
image = Image.open(StringIO.StringIO(data))
if not result:
result = image
else:
try:
result.paste(image, None, image)
except Exception, E:
raise Exception("Could not combine images: Is it possible that some layers are not \n8-bit transparent images? \n(Error was: %s)" % E)
buffer = StringIO.StringIO()
result.save(buffer, result.format)
buffer.seek(0)
return (format, buffer.read())
else:
return (tile.format, tile.data)
def modPythonHandler (apacheReq, service):
from mod_python import apache, util
try:
if apacheReq.headers_in.has_key("X-Forwarded-Host"):
host = "http://" + apacheReq.headers_in["X-Forwarded-Host"]
else:
host = "http://" + apacheReq.headers_in["Host"]
host += apacheReq.uri[:-len(apacheReq.path_info)]
format, image = service.dispatchRequest(
util.FieldStorage(apacheReq),
apacheReq.path_info,
apacheReq.method,
host )
apacheReq.content_type = format
apacheReq.status = apache.HTTP_OK
if format.startswith("image/"):
if service.cache.sendfile:
apacheReq.headers_out['X-SendFile'] = image
if service.cache.expire:
apacheReq.headers_out['Expires'] = email.Utils.formatdate(time.time() + service.cache.expire, False, True)
apacheReq.set_content_length(len(image))
apacheReq.send_http_header()
if format.startswith("image/") and service.cache.sendfile:
apacheReq.write("")
else:
apacheReq.write(image)
except TileCacheException, E:
apacheReq.content_type = "text/plain"
apacheReq.status = apache.HTTP_NOT_FOUND
apacheReq.send_http_header()
apacheReq.write("An error occurred: %s\n" % (str(E)))
except Exception, E:
apacheReq.content_type = "text/plain"
apacheReq.status = apache.HTTP_INTERNAL_SERVER_ERROR
apacheReq.send_http_header()
apacheReq.write("An error occurred: %s\n%s\n" % (
str(E),
"".join(traceback.format_tb(sys.exc_traceback))))
return apache.OK
def wsgiHandler (environ, start_response, service):
from paste.request import parse_formvars
try:
path_info = host = ""
if "PATH_INFO" in environ:
path_info = environ["PATH_INFO"]
if "HTTP_X_FORWARDED_HOST" in environ:
host = "http://" + environ["HTTP_X_FORWARDED_HOST"]
elif "HTTP_HOST" in environ:
host = "http://" + environ["HTTP_HOST"]
host += environ["SCRIPT_NAME"]
req_method = environ["REQUEST_METHOD"]
fields = parse_formvars(environ)
format, image = service.dispatchRequest( fields, path_info, req_method, host )
headers = [('Content-Type',format)]
if format.startswith("image/"):
if service.cache.sendfile:
headers.append(('X-SendFile', image))
if service.cache.expire:
headers.append(('Expires', email.Utils.formatdate(time.time() + service.cache.expire, False, True)))
start_response("200 OK", headers)
if service.cache.sendfile and format.startswith("image/"):
return []
else:
return [image]
except TileCacheException, E:
start_response("404 Tile Not Found", [('Content-Type','text/plain')])
return ["An error occurred: %s" % (str(E))]
except Exception, E:
start_response("500 Internal Server Error", [('Content-Type','text/plain')])
return ["An error occurred: %s\n%s\n" % (
str(E),
"".join(traceback.format_tb(sys.exc_traceback)))]
def cgiHandler (service):
try:
params = {}
input = cgi.FieldStorage()
for key in input.keys(): params[key] = input[key].value
path_info = host = ""
if "PATH_INFO" in os.environ:
path_info = os.environ["PATH_INFO"]
if "HTTP_X_FORWARDED_HOST" in os.environ:
host = "http://" + os.environ["HTTP_X_FORWARDED_HOST"]
elif "HTTP_HOST" in os.environ:
host = "http://" + os.environ["HTTP_HOST"]
host += os.environ["SCRIPT_NAME"]
req_method = os.environ["REQUEST_METHOD"]
format, image = service.dispatchRequest( params, path_info, req_method, host )
print "Content-type: %s" % format
if format.startswith("image/"):
if service.cache.sendfile:
print "X-SendFile: %s" % image
if service.cache.expire:
print "Expires: %s" % email.Utils.formatdate(time.time() + service.cache.expire, False, True)
print ""
if (not service.cache.sendfile) or (not format.startswith("image/")):
if sys.platform == "win32":
binaryPrint(image)
else:
print image
except TileCacheException, E:
print "Cache-Control: max-age=10, must-revalidate" # make the client reload
print "Content-type: text/plain\n"
print "An error occurred: %s\n" % (str(E))
except Exception, E:
print "Cache-Control: max-age=10, must-revalidate" # make the client reload
print "Content-type: text/plain\n"
print "An error occurred: %s\n%s\n" % (
str(E),
"".join(traceback.format_tb(sys.exc_traceback)))
theService = {}
lastRead = {}
def handler (apacheReq):
global theService, lastRead
options = apacheReq.get_options()
cfgs = cfgfiles
fileChanged = False
if options.has_key("TileCacheConfig"):
configFile = options["TileCacheConfig"]
lastRead[configFile] = time.time()
cfgs = cfgs + (configFile,)
try:
cfgTime = os.stat(configFile)[8]
fileChanged = lastRead[configFile] < cfgTime
except:
pass
else:
configFile = 'default'
if not theService.has_key(configFile) or fileChanged:
theService[configFile] = Service.load(*cfgs)
return modPythonHandler(apacheReq, theService[configFile])
def wsgiApp (environ, start_response):
global theService
cfgs = cfgfiles
if not theService:
theService = Service.load(*cfgs)
return wsgiHandler(environ, start_response, theService)
def binaryPrint(binary_data):
"""This function is designed to work around the fact that Python
in Windows does not handle binary output correctly. This function
will set the output to binary, and then write to stdout directly
rather than using print."""
try:
import msvcrt
msvcrt.setmode(sys.__stdout__.fileno(), os.O_BINARY)
except:
pass
sys.stdout.write(binary_data)
def paste_deploy_app(global_conf, full_stack=True, **app_conf):
if 'tilecache_config' in app_conf:
cfgfiles = (app_conf['tilecache_config'],)
else:
raise TileCacheException("No tilecache_config key found in configuration. Please specify location of tilecache config file in your ini file.")
theService = Service.load(*cfgfiles)
if 'exception' in theService.metadata:
raise theService.metadata['exception']
def pdWsgiApp (environ,start_response):
return wsgiHandler(environ,start_response,theService)
return pdWsgiApp
if __name__ == '__main__':
svc = Service.load(*cfgfiles)
cgiHandler(svc)
tilecache-2.11/TileCache/PaxHeader/Services 000755 777777 777777 00000000257 11456036475 022530 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142716
38 LIBARCHIVE.creationtime=1287142716
24 SCHILY.dev=234881029
22 SCHILY.ino=3311408
19 SCHILY.nlink=12
tilecache-2.11/TileCache/Services/ 000755 473017214730172100000000000 11456036475 020763 5 ustar 00christos christos 000000 000000 tilecache-2.11/TileCache/PaxHeader/Swarm.py 000644 777777 777777 00000000210 11456032102 022426 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142716
20 atime=1287142716
24 SCHILY.dev=234881029
22 SCHILY.ino=3311406
18 SCHILY.nlink=1
tilecache-2.11/TileCache/Swarm.py 000644 473017214730172100000017604 11456032102 020632 0 ustar 00christos christos 000000 000000 # BSD Licensed, Copyright (c) 2006-2010 TileCache Contributors
import struct, time
from sha import sha
from bisect import bisect_left
from Layer import Layer, Tile
from Client import WMS
from Service import Service
class Message (object):
types = ("PING", "PONG", "GET", "PUT", "DELETE")
header = "!20sLHH"
header_len = struct.calcsize(header)
tilespec = "!31pHLL"
tilespec_len = struct.calcsize(tilespec)
def __init__ (self, msgtype, key, seq, tile = None):
self.key = key
self.seq_id = seq
self.type = msgtype
self.tile = tile
def _thaw (classobj, msgtxt, layers):
key, seq, msgtype, crc = struct.unpack( classobj.header,
msgtxt[:classobj.header_len] )
msg = classobj( classobj.types[msgtype], key, seq )
msg.checksum = crc
dispatch = getattr(msg, "thaw_" + msg.type)
dispatch( msgtxt[classobj.header_len:], layers )
return msg
thaw = classmethod(_thaw)
def thaw_PING (self, msgtxt, layers):
pass
def thaw_PONG (self, msgtxt, layers):
self.ping_id = struct.unpack("!L", msgtxt)
def thaw_GET (self, msgtxt, layers):
layername, level, row, col = struct.unpack(self.tilespec, msgtxt)
self.tile = Tile(layers[layername], row, col, level)
def thaw_PUT (self, msgtxt, layers):
self.thaw_GET(msgtxt[:self.tilespec_len], layers)
self.tile.data = msgtxt[self.tilespec_len:]
def thaw_DELETE (self, msgtxt, layers):
layername, level, minrow, mincol, maxrow, maxcol = \
struct.unpack("!31pHLLLL", msgtxt)
self.layer = layer[layername]
self.level = level
self.box = (minrow, mincol, maxrow, maxcol)
def freeze (self):
msgtype, name = filter( lambda x: x[1] == self.type,
enumerate(self.types) )[0]
msgtxt = struct.pack( self.header,
self.key, self.seq_id, msgtype, 0 )
dispatch = getattr(self, "freeze_" + self.type)
msgtxt += dispatch()
return msgtxt
def freeze_PING (self):
return ""
def freeze_PONG (self):
return struct.pack("!L", self.ping_id)
def freeze_GET (self):
tile = self.tile
return struct.pack(self.tilespec,
tile.layer.name, tile.z, tile.x, tile.y)
def freeze_PUT (self):
return self.freeze_GET() + self.tile.data
def freeze_DELETE (self):
return struct.pack("!31pHLLLL",
self.tile.layer.name, self.level, *self.box)
class Peer (object):
min_timeout = 15
def __init__ (self, key = None, address = None, weight = 10.0):
self.address = address
self.key = key
self.weight = float(weight)
self.seq_id = 0L
self.timeout = self.min_timeout
class Client (Peer):
max_ring_inserts = 64
replication = 3
def __init__ (self, service = None, **kwargs):
Peer.__init__(self, **kwargs)
self.seq_id = long( time.time() )
self.ring = []
self.peers = {}
self.requests = {}
self.config = service
self.server = None
def tile_key (self, tile):
id = tile.layer + struct.pack("xHLL", tile.z, tile.x, tile.y)
return sha(id).digest()
def message (self, type, tile = None):
self.seq_id += 1
return Message(type, self.key, self.seq_id, tile)
def drop_timeout (self, peer):
if peer.timeout: peer.timeout -= 1
def schedule_timeout (self, peer):
self.schedule(1.0, self.drop_timeout, peer)
def set_put_callback (self, tile, callback):
key = self.tile_key(tile)
if key not in self.requests:
self.requests[key] = []
self.requests[key].append(callback)
def trigger_put_callbacks (self, tile):
key = self.tile_key(tile)
if key not in self.requests:
return
for callback in self.requests[key]:
callback(tile)
del self.requests[key]
def send (self, peer, msg):
raise NotImplementedError()
def schedule (self, when, callback, *args):
raise NotImplementedError()
def load_peers (self):
raise NotImplementedError()
self.schedule(15.0, self.load_peers)
def load_peers_from_string(self, data):
directory = []
found = {}
for line in data.split("\n"):
key, ip, port, weight = line.split(" ")
directory.append(Peer(key, (ip, port), weight))
self.set_peers(directory)
def set_peers (self, peers):
new_peers = dict(map(lambda p: (p.key, p), peers))
for key, peer in new_peers:
if key in self.peers: # already have it
continue
else:
self.peers[key] = peer # don't? then add it
for key, peer in self.peers:
if key not in new_peers:
del self.peers[key] # don't need it anymore
self.rebalance_peers()
def rebalance_peers (self):
ring = []
peers = self.peers.values()
total_weight = sum([p.weight for p in peers]) + 1.0
for peer in peers:
normal_weight = peer.weight / total_weight * self.max_ring_inserts
self.ring.append((peer.key, peer))
for i in range(1, int(normal_weight)):
subkey = sha(peer.key + chr(i)).digest()
self.ring.append((subkey, peer))
ring.sort()
self.ring = ring
def select_peers (self, key, count = replication):
if type(key) is Tile:
key = self.tile_key(key)
start = bisect_left(self.ring, (key,))
cursor = start
selected = []
while len(selected) < count:
peer = self.ring[cursor][1]
if peer.timeout and peer.key != self.key:
selected.append(peer)
if cursor == len(self.ring):
cursor = 0
else:
cursor += 1
if cursor == start: break
return selected
def send_GET (self, tile, callback = None):
if callable(callback):
self.set_put_callback(tile, callback)
for target in self.select_peers(tile):
msg = self.message("GET", tile)
self.send(target, msg)
self.schedule_timeout(target)
def send_PUT (self, tile):
for target in self.select_peers(tile):
msg = self.message("PUT", tile)
self.send(target, msg)
def send_PING (self, peer):
self.send( peer, self.message("PING") )
self.schedule_timeout(peer)
def send_PONG (self, ping):
msg = self.message("PONG")
msg.ping_id = ping.seq_id
peer = self.peers[ping.key]
self.send( peer, msg )
def handle (self, thunk, (host, port)):
msg = Message.thaw(thunk, self.config.layers)
peer = self.peers[msg.key]
# validate originating host/port here
peer.timeout = self.max_timeout
dispatch = getattr(self, "handle_" + msg.type)
dispatch(peer, msg)
def handle_GET (self, peer, msg):
data = self.config.cache.get(msg.tile)
if data:
msg.tile.data = data
reply = self.message("PUT", msg.tile)
self.send( peer, reply )
else:
self.send_PONG( msg )
def handle_PUT (self, peer, msg):
self.config.cache.set(msg.tile, msg.tile.data)
self.handle_put_callbacks(msg.tile)
def handle_PING (self, peer, msg):
self.send_PONG(msg)
def handle_PONG (self, peer, msg):
# already reset peer timeout, nothing to be done
pass
def handle_DELETE (self, peer, msg):
# not implemented yet
pass
tilecache-2.11/TileCache/Services/PaxHeader/__init__.py 000644 777777 777777 00000000210 10725437107 024673 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142716
20 atime=1287142716
24 SCHILY.dev=234881029
22 SCHILY.ino=3311414
18 SCHILY.nlink=1
tilecache-2.11/TileCache/Services/__init__.py 000644 473017214730172100000000000 10725437107 023055 0 ustar 00christos christos 000000 000000 tilecache-2.11/TileCache/Services/PaxHeader/JSON.py 000644 777777 777777 00000000210 11027761617 023707 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142716
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311409
18 SCHILY.nlink=1
tilecache-2.11/TileCache/Services/JSON.py 000644 473017214730172100000002264 11027761617 022107 0 ustar 00christos christos 000000 000000 from TileCache.Services.TMS import TMS
from TileCache.Service import Request, Capabilities
import simplejson
class JSON(TMS):
def parse(self, fields, path, host):
layers = {}
type = "object"
if fields.has_key("type") and fields['type'] == "list":
layers = []
type = "list"
match_srs = False
if 'srs' in fields:
match_srs = fields['srs']
for name, layer in self.service.layers.items():
if match_srs and layer.srs != match_srs:
continue
data = {
'bbox': layer.bbox,
'data_extent': layer.data_extent,
'resolutions': layer.resolutions,
'metadata': layer.metadata,
'srs': layer.srs,
'units': layer.units,
'name': name,
}
if type == "list":
layers.append(data)
else:
layers[name] = data
obj = {'layers': layers}
data = simplejson.dumps(obj)
if 'callback' in fields:
data = "%s(%s)" % (fields['callback'], data)
return ("application/json", data)
tilecache-2.11/TileCache/Services/PaxHeader/KML.py 000644 777777 777777 00000000210 11456032102 023543 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311415
18 SCHILY.nlink=1
tilecache-2.11/TileCache/Services/KML.py 000644 473017214730172100000005375 11456032102 021751 0 ustar 00christos christos 000000 000000 # BSD Licensed, Copyright (c) 2006-2010 TileCache Contributors
from TileCache.Service import Request, Capabilities
from TileCache.Services.TMS import TMS
import TileCache.Layer as Layer
class KML(TMS):
def parse (self, fields, path, host):
tile = TMS.parse(self,fields, path, host)
kml = self.generate_kml_doc(tile, base_path=host)
return ("application/vnd.google-earth.kml+xml", kml)
def generate_kml_doc(self, tile, base_path="", include_wrapper = True):
tiles = [
Layer.Tile(tile.layer, tile.x << 1, tile.y << 1, tile.z + 1),
Layer.Tile(tile.layer, (tile.x << 1) + 1, tile.y << 1, tile.z + 1),
Layer.Tile(tile.layer, (tile.x << 1) + 1, (tile.y << 1) + 1, tile.z + 1),
Layer.Tile(tile.layer, tile.x << 1 , (tile.y << 1) + 1, tile.z + 1)
]
network_links = []
for single_tile in tiles:
if single_tile.z >= len(tile.layer.resolutions):
continue
b = single_tile.bounds()
network_links.append("""tile256-1%s%s%s%s%s/1.0.0/%s/%s/%s/%s.kmlonRegion""" % (b[3], b[1], b[2], b[0], base_path, single_tile.layer.name, single_tile.z, single_tile.x, single_tile.y))
b = tile.bounds()
kml = []
if include_wrapper:
kml.append( """
""")
if tile.z == len(tile.layer.resolutions) - 1:
max_lod_pixels = -1
else:
max_lod_pixels = 512
kml.append("""
256%d%s%s%s%s%s%s/1.0.0/%s/%s/%s/%s%s%s%s%s
%s
""" % (max_lod_pixels, b[3], b[1], b[2], b[0], tile.z, base_path, tile.layer.name, tile.z, tile.x, tile.y, b[3], b[1], b[2], b[0], "\n".join(network_links)))
if include_wrapper:
kml.append("""""" )
kml = "\n".join(kml)
return kml
tilecache-2.11/TileCache/Services/PaxHeader/MGMaps.py 000644 777777 777777 00000000210 11456032102 024244 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311417
18 SCHILY.nlink=1
tilecache-2.11/TileCache/Services/MGMaps.py 000644 473017214730172100000001771 11456032102 022446 0 ustar 00christos christos 000000 000000 # BSD Licensed, Copyright (c) 2006-2010 TileCache Contributors
from TileCache.Service import Request, Capabilities
import TileCache.Layer as Layer
class MGMaps (Request):
def parse (self, fields, path, host):
param = {}
for key in ['layer', 'zoom', 'x', 'y']:
if fields.has_key(key.upper()):
param[key] = fields[key.upper()]
elif fields.has_key(key):
param[key] = fields[key]
else:
param[key] = ""
return self.getMap(param)
def getMap (self, param):
layer = self.getLayer(param["layer"])
level = int(param["zoom"])
level = 17 - level
x = float(param["x"])
y = float(param["y"])
res = layer.resolutions[level]
maxY = int(
round(
(layer.bbox[3] - layer.bbox[1]) /
(res * layer.size[1])
)
) - 1
tile = Layer.Tile(layer, x, maxY - y, level)
return tile
tilecache-2.11/TileCache/Services/PaxHeader/TileService.py 000644 777777 777777 00000000210 11456032102 025336 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142716
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311412
18 SCHILY.nlink=1
tilecache-2.11/TileCache/Services/TileService.py 000644 473017214730172100000001514 11456032102 023533 0 ustar 00christos christos 000000 000000 # BSD Licensed, Copyright (c) 2006-2010 TileCache Contributors
from TileCache.Service import Request, Capabilities
import TileCache.Layer as Layer
class TileService (Request):
def parse (self, fields, path, host):
param = {}
for key in ['interface', 'version', 'dataset', 'level', 'x', 'y', 'request']:
if fields.has_key(key.upper()):
param[key] = fields[key.upper()]
elif fields.has_key(key):
param[key] = fields[key]
else:
param[key] = ""
return self.getMap(param)
def getMap (self, param):
layer = self.getLayer(param["dataset"])
level = int(param["level"])
y = float(param["y"])
x = float(param["x"])
tile = Layer.Tile(layer, x, y, level)
return tile
tilecache-2.11/TileCache/Services/PaxHeader/TMS.py 000644 777777 777777 00000000210 11456032102 023563 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311416
18 SCHILY.nlink=1
tilecache-2.11/TileCache/Services/TMS.py 000644 473017214730172100000007135 11456032102 021765 0 ustar 00christos christos 000000 000000 # BSD Licensed, Copyright (c) 2006-2010 TileCache Contributors
from TileCache.Service import Request, Capabilities
import TileCache.Layer as Layer
class TMS (Request):
def parse (self, fields, path, host):
# /1.0.0/global_mosaic/0/0/0.jpg
parts = filter( lambda x: x != "", path.split("/") )
if not host[-1] == "/": host = host + "/"
if len(parts) < 1:
return self.serverCapabilities(host)
elif len(parts) < 2:
return self.serviceCapabilities(host, self.service.layers)
else:
layer = self.getLayer(parts[1])
if len(parts) < 3:
return self.layerCapabilities(host, layer)
else:
parts[-1] = parts[-1].split(".")[0]
tile = None
if layer.tms_type == "google" or (fields.has_key('type') and fields['type'] == 'google'):
res = layer.resolutions[int(parts[2])]
maxY = int(
round(
(layer.bbox[3] - layer.bbox[1]) /
(res * layer.size[1])
)
) - 1
tile = Layer.Tile(layer, int(parts[3]), maxY - int(parts[4]), int(parts[2]))
else:
tile = Layer.Tile(layer, int(parts[3]), int(parts[4]), int(parts[2]))
return tile
def serverCapabilities (self, host):
return Capabilities("text/xml", """
""" % host)
def serviceCapabilities (self, host, layers):
xml = """
"""
for name, layer in layers.items():
profile = "none"
if (layer.srs == "EPSG:4326"): profile = "global-geodetic"
elif (layer.srs == "OSGEO:41001"): profile = "global-mercator"
xml += """
""" % (host, name, layer.srs, layer.name, profile)
xml += """
"""
return Capabilities("text/xml", xml)
def layerCapabilities (self, host, layer):
tms_type = layer.tms_type or "default"
xml = """
%s%s%s
""" % (host, tms_type, layer.name, layer.description, layer.srs, layer.bbox[0], layer.bbox[1],
layer.bbox[2], layer.bbox[3], layer.bbox[0], layer.bbox[1],
layer.size[0], layer.size[1], layer.format(), layer.extension)
for z, res in enumerate(layer.resolutions):
xml += """
""" % (
host, layer.name, z, res, z)
xml += """
"""
return Capabilities("text/xml", xml)
tilecache-2.11/TileCache/Services/PaxHeader/VETMS.py 000644 777777 777777 00000000210 11456032102 024016 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142716
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311413
18 SCHILY.nlink=1
tilecache-2.11/TileCache/Services/VETMS.py 000644 473017214730172100000003562 11456032102 022220 0 ustar 00christos christos 000000 000000 # BSD Licensed, Copyright (c) 2006-2010 TileCache Contributors
from TileCache.Service import Request, Capabilities
import TileCache.Layer as Layer
class VETMS (Request):
"""
Support for Virtual Earth quadkey-based URLs.
?ve=true&layer=global_mosaic&tile=000.jpg
"""
def parse (self, fields, path, host):
"""Take in VETMS params and return a tile."""
for key in ['layer', 'tile']:
if fields.has_key(key.upper()):
fields[key] = fields[key.upper()]
elif not fields.has_key(key):
fields[key] = ""
layer = self.getLayer(fields['layer'])
tilenumber = str(fields['tile'])
quadkey = tilenumber.split(".")[0]
tile = None
cell = self.unquad(quadkey)
tile = Layer.Tile(layer, cell[0], cell[1], cell[2])
return tile
def unquad (self, quad):
"""
Returns x/y/z ints based on a quadkey.
>>> ve = VETMS({})
>>> ve.unquad("1")
[1, 1, 1]
>>> ve.unquad("")
[0, 0, 0]
>>> ve.unquad("02")
[0, 2, 2]
"""
z = len(quad)
col = int(0)
row = int(pow(2, z)-1)
quadint = int(0)
for i in range (0, z):
quadint = int(quad[i])
tmp = int(pow(2, z-(i+1)))
if (quadint == 1):
col += tmp
elif (quadint == 2):
row -= tmp
elif (quadint == 3):
col += tmp
row -= tmp
cell = [int(col), int(row), int(z)]
return cell
def serverCapabilities (self, host):
"""Report capabilities for VETMS."""
return Capabilities("text/xml", """
""" % host)
tilecache-2.11/TileCache/Services/PaxHeader/WMS.py 000644 777777 777777 00000000210 11456032102 023566 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311418
18 SCHILY.nlink=1
tilecache-2.11/TileCache/Services/WMS.py 000644 473017214730172100000012321 11456032102 021761 0 ustar 00christos christos 000000 000000 # BSD Licensed, Copyright (c) 2006-2010 TileCache Contributors
from TileCache.Service import Request, Capabilities
import TileCache.Layer as Layer
class WMS (Request):
def parse (self, fields, path, host):
param = {}
for key in ['bbox', 'layers', 'request', 'version']:
if fields.has_key(key.upper()):
param[key] = fields[key.upper()]
elif fields.has_key(key):
param[key] = fields[key]
else:
param[key] = ""
if param["request"] == "GetCapabilities":
return self.getCapabilities(host + path, param)
else:
return self.getMap(param)
def getMap (self, param):
bbox = map(float, param["bbox"].split(","))
layers = param["layers"].split(",")
tiles = []
for name in layers:
tile = self.getLayer(name).getTile(bbox)
if not tile:
raise Exception(
"couldn't calculate tile index for layer %s from (%s)"
% (layer.name, bbox))
tiles.append(tile)
if len(tiles) > 1:
return tiles
else:
return tiles[0]
def getCapabilities (self, host, param):
if host[-1] not in "?&":
if "?" in host:
host += "&"
else:
host += "?"
metadata = self.service.metadata
if "description" in metadata:
description = metadata["description"]
else:
description = ""
formats = {}
for layer in self.service.layers.values():
formats[layer.format()] = 1
formats = formats.keys()
xml = """
]>
OGC:WMS%s
""" % (description, host)
xml += """
application/vnd.ogc.wms_xml""" % (host)
xml += """
"""
for format in formats:
xml += """
%s\n""" % format
xml += """
""" % (host)
xml += """
text/plain"""
for name, layer in self.service.layers.items():
resolutions = " ".join(["%.20f" % r for r in layer.resolutions])
xml += """
%s%s%d%d%s%s""" % (
layer.srs, layer.srs, layer.bbox[0], layer.bbox[1],
layer.bbox[2], layer.bbox[3], resolutions, layer.size[0],
layer.size[1], layer.format(), name )
xml += """
TileCache Layers"""
for name, layer in self.service.layers.items():
xml += """
%s%s%s""" % (
name, layer.name, layer.srs, layer.srs,
layer.bbox[0], layer.bbox[1], layer.bbox[2], layer.bbox[3])
xml += """
"""
return Capabilities("text/xml", xml)
tilecache-2.11/TileCache/Services/PaxHeader/WMTS.py 000644 777777 777777 00000000210 11456032102 023712 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142716
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311411
18 SCHILY.nlink=1
tilecache-2.11/TileCache/Services/WMTS.py 000644 473017214730172100000002313 11456032102 022105 0 ustar 00christos christos 000000 000000 # BSD Licensed, Copyright (c) 2006-2010 TileCache Contributors
from TileCache.Service import Request, Capabilities, TileCacheException
import TileCache.Layer as Layer
class WMTS (Request):
meters_per_unit = { 'degrees': 111118.752,
'meters': 1,
'feet': 0.3048
}
def parse (self, fields, path, host):
for key in ['scale','layer','tilerow','tilecol']:
if fields.has_key(key.upper()):
fields[key] = fields[key.upper()]
elif not fields.has_key(key):
fields[key] = ""
layer = self.getLayer(fields['layer'])
if not layer.units:
raise TileCacheException("No units were specified on the layer. WMTS support requires units to be defined for the layer.")
res = .00028 * float(fields['scale']) / self.meters_per_unit[layer.units]
z = layer.getLevel(res, layer.size)
tile = None
maxY = int(
round(
(layer.bbox[3] - layer.bbox[1]) /
(res * layer.size[1])
)
) - 1
tile = Layer.Tile(layer, int(fields['tilecol']), maxY - int(fields['tilerow']), z)
return tile
tilecache-2.11/TileCache/Services/PaxHeader/WorldWind.py 000644 777777 777777 00000000210 11456032102 025031 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142716
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311410
18 SCHILY.nlink=1
tilecache-2.11/TileCache/Services/WorldWind.py 000644 473017214730172100000006656 11456032102 023242 0 ustar 00christos christos 000000 000000 # BSD Licensed, Copyright (c) 2006-2010 TileCache Contributors
from TileCache.Service import Request, Capabilities
import TileCache.Layer as Layer
class WorldWind (Request):
def parse (self, fields, path, host):
param = {}
for key in ['t', 'l', 'x', 'y', 'request']:
if fields.has_key(key.upper()):
param[key] = fields[key.upper()]
elif fields.has_key(key):
param[key] = fields[key]
else:
param[key] = ""
if param["request"] == "GetCapabilities" or param["request"] == "metadata":
return self.getCapabilities(host + path, param)
else:
return self.getMap(param)
def getMap (self, param):
layer = self.getLayer(param["t"])
level = int(param["l"])
y = float(param["y"])
x = float(param["x"])
tile = Layer.Tile(layer, x, y, level)
return tile
def getCapabilities (self, host, param):
metadata = self.service.metadata
if "description" in metadata:
description = metadata["description"]
else:
description = ""
formats = {}
for layer in self.service.layers.values():
formats[layer.format()] = 1
formats = formats.keys()
xml = """
"""
for name, layer in self.service.layers.items():
if (layer.srs != "EPSG:4326"): continue
xml += """
%sLayer: %s0%s%s%s%sfalse%s%s%s%s%s%sSRS:%s
""" % (name, name, layer.description, float(layer.bbox[0]), float(layer.bbox[1]),
float(layer.bbox[2]), float(layer.bbox[3]), layer.resolutions[0] * layer.size[0],
len(layer.resolutions), layer.size[0], layer.extension, host,
name, layer.srs)
xml += """
"""
return Capabilities("text/xml", xml)
tilecache-2.11/TileCache/Peer/PaxHeader/Twisted.py 000644 777777 777777 00000000210 11456032102 023653 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311434
18 SCHILY.nlink=1
tilecache-2.11/TileCache/Peer/Twisted.py 000644 473017214730172100000002103 11456032102 022043 0 ustar 00christos christos 000000 000000 # BSD Licensed, Copyright (c) 2006-2010 TileCache Contributors
from Swarm import Message, Client
from twisted.internet.protocol import DatagramProtocol
from twisted.web import getPage
from twisted.internet import reactor
class TwistedClient (DatagramProtocol, Client):
directoryURL = "..."
def __init__ (self, service, key, weight = 10.0, *args, **kwargs):
DatagramProtocol.__init__(self, *args, **kwargs)
Client.__init__(self, service, key, None, weight)
def datagramReceived(self, data, (host, port)):
self.handle(data, (host, port))
def send (self, peer, msg):
self.transport.write( msg.freeze(), peer.address )
def schedule (self, when, callback, *args):
reactor.callLater(time.time() + when, callback, *args)
def load_peers (self):
d = getPage(self.directoryURL)
d.addCallback(self.load_peers_from_string)
self.schedule(15.0, self.load_peers)
def startProtocol (self):
self.load_peers()
if __name__ == '__main__':
reactor.listenUDP(5150, Echo())
reactor.run()
tilecache-2.11/TileCache/Layers/PaxHeader/__init__.py 000644 777777 777777 00000000210 10725446217 024351 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142716
20 atime=1287142716
24 SCHILY.dev=234881029
22 SCHILY.ino=3311400
18 SCHILY.nlink=1
tilecache-2.11/TileCache/Layers/__init__.py 000644 473017214730172100000000000 10725446217 022533 0 ustar 00christos christos 000000 000000 tilecache-2.11/TileCache/Layers/PaxHeader/ArcXML.py 000644 777777 777777 00000000210 11456032102 023662 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142716
20 atime=1287142716
24 SCHILY.dev=234881029
22 SCHILY.ino=3311403
18 SCHILY.nlink=1
tilecache-2.11/TileCache/Layers/ArcXML.py 000644 473017214730172100000011345 11456032102 022062 0 ustar 00christos christos 000000 000000 # BSD Licensed, Copyright (c) 2006-2010 TileCache Contributors
"""
ArcXML support. This layer will make requests to an ArcIMS server.
"""
from TileCache.Layer import MetaLayer
from TileCache.Service import TileCacheException
import urllib
import xml.dom.minidom as m
class ArcXML(MetaLayer):
config_properties = [
{'name':'name', 'description': 'Name of Layer'},
{'name':'url', 'description': 'URL of Remote Layer'},
{'name':'layers', 'description': 'Comma seperated list of layers associated with this layer.'},
{'name':'off_layers', 'description': 'Comma-seperated layers to turn on'},
{'name':'projection', 'description': 'WKT String, or, if the string starts with "@", a file containing a WKT string.'}
] + MetaLayer.config_properties
def __init__ (self, name, url = None, off_layers = "",
projection = None, **kwargs):
"""
Accepts projection in one of two forms:
* Raw string
* String beginning with @, in which case string is treated as filename
"""
MetaLayer.__init__(self, name, **kwargs)
self.url = url
self.off_layers = off_layers
self.projection = None
if projection is not None:
if projection.startswith("@"):
self.projection = open(projection[1:]).read()
else:
self.projection = projection
def gen_xml(self, tile):
"""
>>> from TileCache.Layer import Tile
>>> l = ArcXML("foo", projection="fooproj")
>>> xml = l.gen_xml(Tile(l, 0,0,0))
>>> print xml.replace("\\n", "")
>>> doc = m.parseString(xml)
>>> feat_coord_sys = doc.getElementsByTagName("FEATURECOORDSYS")
>>> len(feat_coord_sys)
1
>>> feat_coord_sys[0].getAttribute("string")
u'fooproj'
>>> l = ArcXML("foo")
>>> xml = l.gen_xml(Tile(l, 0,0,0))
>>> doc = m.parseString(xml)
>>> feat_coord_sys = doc.getElementsByTagName("FEATURECOORDSYS")
>>> len(feat_coord_sys)
0
>>> import os
>>> f = open('tmp_tc_test_file', 'w')
>>> f.write('foo<>"][')
>>> f.close()
>>> l = ArcXML("foo", projection="@tmp_tc_test_file")
>>> xml = l.gen_xml(Tile(l, 0,0,0))
>>> doc = m.parseString(xml)
>>> feat_coord_sys = doc.getElementsByTagName("FEATURECOORDSYS")
>>> feat_coord_sys[0].toxml()
u''
>>> os.unlink("tmp_tc_test_file")
"""
layers = []
off_layers = []
for layer_id in self.layers.split(","):
if layer_id.strip():
layers.append('' % layer_id)
for layer_id in self.off_layers.split(","):
if layer_id.strip():
off_layers.append('' % layer_id)
bbox = tile.bounds()
projection_text = ""
if self.projection:
doc = m.Document()
feat = doc.createElement("FEATURECOORDSYS")
feat.setAttribute("string", self.projection)
projection_text = "%s\n%s" % (
feat.toxml(), feat.toxml().replace("FEATURE", "FILTER"))
return """
%s
%s
%s
""" % (bbox[0], bbox[1], bbox[2], bbox[3],
projection_text, tile.size()[0], tile.size()[1],
"\n".join(layers), "\n".join(off_layers))
def renderTile(self, tile):
xml = self.gen_xml(tile)
try:
xmldata = urllib.urlopen(self.url, xml).read()
except Exception, error:
raise TileCacheException("Error fetching URL. Exception was: %s\n Input XML:\n %s " % (error, xml))
try:
doc = m.parseString(xmldata)
img_url = doc.getElementsByTagName("OUTPUT")[0].attributes['url'].value
except Exception, error:
raise TileCacheException("Error fetching URL. Exception was: %s\n Output XML: \n%s\n\nInput XML:\n %s " % (error, xmldata, xml))
tile.data = urllib.urlopen(img_url).read()
return tile.data
tilecache-2.11/TileCache/Layers/PaxHeader/GDAL.py 000644 777777 777777 00000000210 11456032102 023303 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142716
20 atime=1287142716
24 SCHILY.dev=234881029
22 SCHILY.ino=3311405
18 SCHILY.nlink=1
tilecache-2.11/TileCache/Layers/GDAL.py 000644 473017214730172100000012741 11456032102 021504 0 ustar 00christos christos 000000 000000 # BSD Licensed, Copyright (c) 2006-2010 TileCache Contributors
from TileCache.Layer import MetaLayer
import osgeo.gdal as gdal
import osgeo.gdal_array as gdalarray
import numpy
import PIL
class GDAL(MetaLayer):
"""
The GDAL Layer allows you to set up any GDAL datasource in TileCache.
Areas not covered by the image will be transparent in formats which
support transparency. The GDAL transparency is maintained. All bands
of an image are read from the source file at this time.
This Layer does not support images where north is not up.
Special effort is taken when the GeoTransform on the image is the default
(0.0, 1.0, 0.0, 0.0, 0.0, 1.0): In that case, the geotransform is
replaced with (0.0, 1.0, 0.0, self.ds.RasterYSize, 0.0, -1.0) . This allows
one to use the GDAL layer with non-georeferenced images: Simply specify a
bbox=0,0,size_x,size_y, and then you can use the image in TileCache. This is
likely a better idea than using the Image layer, if you can install GDAL,
since GDAL may be more efficient in managing subsetting of files, especially
geographic sized ones, due to its ability to support overviews on files it is
reading.
This layer depends on:
* GDAL 1.5 with Python Bindings
* PIL
* numpy
"""
config_properties = [
{'name':'name', 'description': 'Name of Layer'},
{'name':'file', 'description': 'GDAL-readable file path.'},
] + MetaLayer.config_properties
def __init__ (self, name, file = None, **kwargs):
MetaLayer.__init__(self, name, **kwargs)
self.ds = gdal.Open(file)
self.geo_transform = self.ds.GetGeoTransform()
if self.geo_transform[2] != 0 or self.geo_transform[4] != 0:
raise Exception("Image is not 'north-up', can not use.")
if self.geo_transform == (0.0, 1.0, 0.0, 0.0, 0.0, 1.0):
self.geo_transform = (0.0, 1.0, 0.0, self.ds.RasterYSize, 0.0, -1.0)
size = [self.ds.RasterXSize, self.ds.RasterYSize]
xform = self.geo_transform
self.data_extent = [
xform[0] + self.ds.RasterYSize * xform[2],
xform[3] + self.ds.RasterYSize * xform[5],
xform[0] + self.ds.RasterXSize * xform[1],
xform[3] + self.ds.RasterXSize * xform[4]
]
def renderTile(self, tile):
import PIL.Image as PILImage
import StringIO
bounds = tile.bounds()
im = None
# If the image is entirely outside the bounds, don't bother doing anything with it:
# just return an 'empty' tile.
if not (bounds[2] < self.data_extent[0] or bounds[0] > self.data_extent[2] or
bounds[3] < self.data_extent[1] or bounds[1] > self.data_extent[3]):
tile_offset_left = tile_offset_top = 0
target_size = tile.size()
off_x = int((bounds[0] - self.geo_transform[0]) / self.geo_transform[1]);
off_y = int((bounds[3] - self.geo_transform[3]) / self.geo_transform[5]);
width_x = int(((bounds[2] - self.geo_transform[0]) / self.geo_transform[1]) - off_x);
width_y = int(((bounds[1] - self.geo_transform[3]) / self.geo_transform[5]) - off_y);
# Prevent from reading off the sides of an image
if off_x + width_x > self.ds.RasterXSize:
oversize_right = off_x + width_x - self.ds.RasterXSize
target_size = [
target_size[0] - int(float(oversize_right) / width_x * target_size[0]),
target_size[1]
]
width_x = self.ds.RasterXSize - off_x
if off_x < 0:
oversize_left = -off_x
tile_offset_left = int(float(oversize_left) / width_x * target_size[0])
target_size = [
target_size[0] - int(float(oversize_left) / width_x * target_size[0]),
target_size[1],
]
width_x = width_x + off_x
off_x = 0
if off_y + width_y > self.ds.RasterYSize:
oversize_bottom = off_y + width_y - self.ds.RasterYSize
target_size = [
target_size[0],
target_size[1] - round(float(oversize_bottom) / width_y * target_size[1])
]
width_y = self.ds.RasterYSize - off_y
if off_y < 0:
oversize_top = -off_y
tile_offset_top = int(float(oversize_top) / width_y * target_size[1])
target_size = [
target_size[0],
target_size[1] - int(float(oversize_top) / width_y * target_size[1]),
]
width_y = width_y + off_y
off_y = 0
bands = self.ds.RasterCount
array = numpy.zeros((target_size[1], target_size[0], bands), numpy.uint8)
for i in range(bands):
array[:,:,i] = gdalarray.BandReadAsArray(self.ds.GetRasterBand(i+1), off_x, off_y, width_x, width_y, target_size[0], target_size[1])
im = PIL.Image.fromarray(array)
big = PIL.Image.new("RGBA", tile.size(), (0,0,0,0))
if im:
big.paste(im, (tile_offset_left, tile_offset_top))
buffer = StringIO.StringIO()
big.save(buffer, self.extension)
buffer.seek(0)
tile.data = buffer.read()
return tile.data
tilecache-2.11/TileCache/Layers/PaxHeader/Image.py 000644 777777 777777 00000000210 11456032102 023616 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142716
20 atime=1287142716
24 SCHILY.dev=234881029
22 SCHILY.ino=3311401
18 SCHILY.nlink=1
tilecache-2.11/TileCache/Layers/Image.py 000644 473017214730172100000005751 11456032102 022022 0 ustar 00christos christos 000000 000000 # BSD Licensed, Copyright (c) 2006-2010 TileCache Contributors
from TileCache.Layer import MetaLayer
class Image(MetaLayer):
"""The ImageLayer allows you to set up any image file in TileCache.
All you need is an image, and a geographic bounds (filebounds),
Which is passed in as a single, comma seperated string in the form
minx,miny,maxx,maxy."""
config_properties = [
{'name':'name', 'description': 'Name of Layer'},
{'name':'file', 'description': 'Location of PIL-readable file.'},
] + MetaLayer.config_properties
def __init__ (self, name, file = None, filebounds = "-180,-90,180,90",
transparency = False, scaling = "nearest", **kwargs):
import PIL.Image as PILImage
MetaLayer.__init__(self, name, **kwargs)
self.file = file
self.filebounds = map(float,filebounds.split(","))
self.image = PILImage.open(self.file)
self.image_size = self.image.size
self.image_res = [(self.filebounds[2] - self.filebounds[0]) / self.image_size[0],
(self.filebounds[3] - self.filebounds[1]) / self.image_size[1]
]
self.scaling = scaling.lower()
if isinstance(transparency, str):
transparency = transparency.lower() in ("true", "yes", "1")
self.transparency = transparency
def renderTile(self, tile):
import PIL.Image as PILImage
import StringIO
bounds = tile.bounds()
size = tile.size()
min_x = (bounds[0] - self.filebounds[0]) / self.image_res[0]
min_y = (self.filebounds[3] - bounds[3]) / self.image_res[1]
max_x = (bounds[2] - self.filebounds[0]) / self.image_res[0]
max_y = (self.filebounds[3] - bounds[1]) / self.image_res[1]
if self.scaling == "bilinear":
scaling = PILImage.BILINEAR
elif self.scaling == "bicubic":
scaling = PILImage.BICUBIC
elif self.scaling == "antialias":
scaling = PILImage.ANTIALIAS
else:
scaling = PILImage.NEAREST
crop_size = (max_x-min_x, max_y-min_y)
if min(min_x, min_y, max_x, max_y) < 0:
if self.transparency and self.image.mode in ("L", "RGB"):
self.image.putalpha(PILImage.new("L", self.image_size, 255));
sub = self.image.transform(crop_size, PILImage.EXTENT, (min_x, min_y, max_x, max_y))
else:
sub = self.image.crop((min_x, min_y, max_x, max_y));
if crop_size[0] < size[0] and crop_size[1] < size[1] and self.scaling == "antialias":
scaling = PILImage.BICUBIC
sub = sub.resize(size, scaling)
buffer = StringIO.StringIO()
if self.image.info.has_key('transparency'):
sub.save(buffer, self.extension, transparency=self.image.info['transparency'])
else:
sub.save(buffer, self.extension)
buffer.seek(0)
tile.data = buffer.read()
return tile.data
tilecache-2.11/TileCache/Layers/PaxHeader/Mapnik.py 000644 777777 777777 00000000210 11456032102 024013 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142716
20 atime=1287142716
24 SCHILY.dev=234881029
22 SCHILY.ino=3311399
18 SCHILY.nlink=1
tilecache-2.11/TileCache/Layers/Mapnik.py 000644 473017214730172100000006323 11456032102 022213 0 ustar 00christos christos 000000 000000 # BSD Licensed, Copyright (c) 2006-2010 TileCache Contributors
import sys
from TileCache.Layer import MetaLayer
class Mapnik(MetaLayer):
config_properties = [
{'name':'name', 'description': 'Name of Layer'},
{'name':'mapfile', 'description': 'Location of Mapnik XML map description.'},
{'name':'projection', 'description': 'Target map projection.'},
{'name':'fonts', 'description': 'Comma-seperated list of fonts to add to the Mapik registered fonts list.'},
] + MetaLayer.config_properties
def __init__ (self, name, mapfile = None, projection = None, fonts = None, **kwargs):
MetaLayer.__init__(self, name, **kwargs)
self.mapfile = mapfile
self.mapnik = None
self.projection = projection
if fonts:
self.fonts = fonts.split(",")
else:
self.fonts = []
def renderTile(self, tile):
import mapnik
if self.mapnik:
m = self.mapnik
else:
if self.fonts:
engine = mapnik.FontEngine.instance()
for font in self.fonts:
engine.register_font(font)
# Init it as 0,0
m = mapnik.Map( 0, 0 )
mapnik.load_map(m,self.mapfile)
if self.projection:
m.srs = self.projection
# Restrict layer list, if requested
if self.layers and self.layers != self.name:
layers = self.layers.split(",")
for layer_num in range(len(m.layers)-1, -1, -1):
l = m.layers[layer_num]
if l.name not in layers:
del m.layers[layer_num]
if self.debug:
print >>sys.stderr, "Removed layer %s loaded from %s, not in list: %s" % (l.name, self.mapfile, layers)
# this will insure that it gets cached in mod_python
self.mapnik = m
# Set the mapnik size to match the size of the current tile
m.width = tile.size()[0]
m.height = tile.size()[1]
bbox = tile.bounds()
bbox = mapnik.Envelope(bbox[0], bbox[1], bbox[2], bbox[3])
m.zoom_to_box(bbox)
im = mapnik.Image( *tile.size() )
mapnik.render(m, im)
if hasattr(im, 'tostring'):
if self.paletted:
data = im.tostring('png256')
else:
data = im.tostring(self.extension)
tile.data = data
return tile.data
elif hasattr(mapnik, 'rawdata'):
data = mapnik.rawdata(im)
import PIL.Image, StringIO
im = PIL.Image.fromstring('RGBA', tile.size(), data)
buffer = StringIO.StringIO()
if self.paletted:
print >>sys.stderr, "Mapnik's 8-bit (png256) format not supported with PIL"
im.save(buffer, self.extension)
buffer.seek(0)
tile.data = buffer.read()
return tile.data
else:
raise Exception("Something is wrong: your version of Mapnik can't create a string from an image.")
tilecache-2.11/TileCache/Layers/PaxHeader/MapServer.py 000644 777777 777777 00000000210 11456032102 024500 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142716
20 atime=1287142716
24 SCHILY.dev=234881029
22 SCHILY.ino=3311402
18 SCHILY.nlink=1
tilecache-2.11/TileCache/Layers/MapServer.py 000644 473017214730172100000004111 11456032102 022671 0 ustar 00christos christos 000000 000000 # BSD Licensed, Copyright (c) 2006-2010 TileCache Contributors
from TileCache.Layer import MetaLayer
class MapServer(MetaLayer):
config_properties = [
{'name':'name', 'description': 'Name of Layer'},
{'name':'mapfile', 'description': 'Location of MapServer map file.'},
] + MetaLayer.config_properties
def __init__ (self, name, mapfile = None, styles = "", **kwargs):
MetaLayer.__init__(self, name, **kwargs)
self.mapfile = mapfile
self.styles = styles
def get_map(self, tile):
# tile is unused here but might be used in a subclass
# where the mapfile config depends on the tile extents or layer
import mapscript
wms = mapscript.mapObj(self.mapfile)
if self.metaBuffer:
try:
# if the metadata is already set, don't override.
wms.getMetaData("labelcache_map_edge_buffer")
except mapscript._mapscript.MapServerError:
# We stick an extra buffer of 5px in there because in the case
# of shields, we want to account for when the shield could get
# cut even though the label that the shield is on isn't.
buffer = -max(self.metaBuffer[0], self.metaBuffer[1]) - 5
wms.setMetaData("labelcache_map_edge_buffer", str(buffer))
return wms
def get_request(self, tile):
import mapscript
req = mapscript.OWSRequest()
req.setParameter("bbox", tile.bbox())
req.setParameter("width", str(tile.size()[0]))
req.setParameter("height", str(tile.size()[1]))
req.setParameter("srs", self.srs)
req.setParameter("format", self.mime_type)
req.setParameter("layers", self.layers)
req.setParameter("styles", self.styles)
req.setParameter("request", "GetMap")
return req
def renderTile(self, tile):
wms = self.get_map(tile)
req = self.get_request(tile)
wms.loadOWSParameters(req)
mapImage = wms.draw()
tile.data = mapImage.getBytes()
return tile.data
tilecache-2.11/TileCache/Layers/PaxHeader/WMS.py 000644 777777 777777 00000000210 11456032102 023242 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142716
20 atime=1287142716
24 SCHILY.dev=234881029
22 SCHILY.ino=3311404
18 SCHILY.nlink=1
tilecache-2.11/TileCache/Layers/WMS.py 000644 473017214730172100000002232 11456032102 021435 0 ustar 00christos christos 000000 000000 # BSD Licensed, Copyright (c) 2006-2010 TileCache Contributors
from TileCache.Layer import MetaLayer
import TileCache.Client as WMSClient
class WMS(MetaLayer):
config_properties = [
{'name':'name', 'description': 'Name of Layer'},
{'name':'url', 'description': 'URL of Remote Layer'},
{'name':'user', 'description': 'Username of remote server: used for basic-auth protected backend WMS layers.'},
{'name':'password', 'description': 'Password of remote server: Use for basic-auth protected backend WMS layers.'},
] + MetaLayer.config_properties
def __init__ (self, name, url = None, user = None, password = None, **kwargs):
MetaLayer.__init__(self, name, **kwargs)
self.url = url
self.user = user
self.password = password
def renderTile(self, tile):
wms = WMSClient.WMS( self.url, {
"bbox": tile.bbox(),
"width": tile.size()[0],
"height": tile.size()[1],
"srs": self.srs,
"format": self.mime_type,
"layers": self.layers,
}, self.user, self.password)
tile.data, response = wms.fetch()
return tile.data
tilecache-2.11/TileCache/Caches/PaxHeader/__init__.py 000644 777777 777777 00000000210 10725446355 024303 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311425
18 SCHILY.nlink=1
tilecache-2.11/TileCache/Caches/__init__.py 000644 473017214730172100000000000 10725446355 022465 0 ustar 00christos christos 000000 000000 tilecache-2.11/TileCache/Caches/PaxHeader/AWSS3.py 000644 777777 777777 00000000210 11456032102 023363 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311426
18 SCHILY.nlink=1
tilecache-2.11/TileCache/Caches/AWSS3.py 000644 473017214730172100000014417 11456032102 021566 0 ustar 00christos christos 000000 000000 # BSD Licensed, Copyright (c) 2006-2010 TileCache Contributors
from TileCache.Cache import Cache
import time
class AWSS3(Cache):
import_error = "Problem importing S3 support library. You must have either boto or the Amazon S3 library.\nErrors:\n * %s"
def __init__ (self, access_key, secret_access_key, use_tms_paths = "False", **kwargs):
self.module = None
try:
import boto.s3
self.s3 = boto.s3
self.module = "boto"
except ImportError, E:
exceptions = [str(E)]
try:
import S3
self.s3 = S3
self.module = "amazon"
except Exception, E:
exceptions.append(str(E))
raise Exception(self.import_error % ('\n * '.join(exceptions)))
Cache.__init__(self, **kwargs)
self.bucket_name = "%s-tilecache" % access_key.lower()
if use_tms_paths.lower() in ("true", "yes", "1"):
use_tms_paths = True
elif use_tms_paths.lower() == "flipped":
use_tms_paths = "google"
self.use_tms_paths = use_tms_paths
if self.module == "amazon":
self.cache = self.s3.AWSAuthConnection(access_key, secret_access_key)
self.cache.create_bucket(self.bucket_name)
else:
self.cache = self.s3.connection.S3Connection(access_key, secret_access_key)
self.bucket = self.cache.create_bucket(self.bucket_name)
def getBotoKey(self, key):
boto_key = self.s3.key.Key(self.bucket)
boto_key.key = key
return boto_key
def getKey(self, tile):
if self.use_tms_paths == True or self.use_tms_paths == "flipped":
grid = tile.layer.grid(tile.z)
y = tile.y
if self.use_tms_paths == "flipped":
y = int(grid[1] - 1 - tile.y)
version = "1.0.0"
path = "/".join(map(str, [version, tile.layer.name, tile.z, tile.x, y]))
path = ".".join(map(str, [path, tile.layer.extension]))
else:
path = "-".join(map(str, [tile.layer.name, tile.z , tile.x, tile.y]))
return path
def get(self, tile):
key = self.getKey(tile)
tile.data = self.getObject(key)
return tile.data
def getObject(self, key):
data = None
if self.module == "amazon":
response = self.cache.get(self.bucket_name, key)
if not response.object.data.startswith(" or ,,
delete_tiles""")
parser.add_option('-z', dest='zoom', help='zoom level for count_tiles (requires layer name)')
parser.add_option('-l', dest='layer', help='layer name for count_tiles')
parser.add_option('-k', dest='key', help='access key for S3')
parser.add_option('-s', dest='secret', help='secret access key for S3')
(options, args) = parser.parse_args()
if not options.key or not options.secret or not args:
parser.print_help()
sys.exit()
def create_prefix(options):
prefix = ""
if options.layer:
prefix = "%s-" % options.layer
if options.zoom:
prefix = "%s%s-" % (prefix, options.zoom)
return prefix
# Debug mode.
a = AWSS3(options.key,
options.secret)
if args[0] == "list_locks":
print ','.join(a.keys({'prefix':'lock-'}))
elif args[0] == "list_keys":
print ','.join(a.keys())
elif args[0] == "count_tiles" or args[0] == "show_tiles":
opts = {
'prefix': create_prefix(options)
}
if args[0] == "show_tiles":
print ",".join(a.keys(opts))
else:
print len(a.keys(opts))
elif args[0] == "delete":
for key in args[1].split(","):
a.deleteObject(key)
elif args[0] == "delete_tiles":
opts = {
'prefix': create_prefix(options)
}
keys = a.keys(opts)
val = raw_input("Are you sure you want to delete %s tiles? (y/n) " % len(keys))
if val.lower() in ['y', 'yes']:
for key in keys:
a.deleteObject(key)
else:
parser.print_help()
tilecache-2.11/TileCache/Caches/PaxHeader/Disk.py 000644 777777 777777 00000000210 11456032102 023415 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311422
18 SCHILY.nlink=1
tilecache-2.11/TileCache/Caches/Disk.py 000644 473017214730172100000010247 11456032102 021615 0 ustar 00christos christos 000000 000000 # BSD Licensed, Copyright (c) 2006-2010 TileCache Contributors
from TileCache.Cache import Cache
import sys, os, time, warnings
class Disk (Cache):
def __init__ (self, base = None, umask = '002', **kwargs):
Cache.__init__(self, **kwargs)
self.basedir = base
self.umask = int(umask, 0)
if sys.platform.startswith("java"):
from java.io import File
self.file_module = File
self.platform = "jython"
else:
self.platform = "cpython"
if not self.access(base, 'read'):
self.makedirs(base)
def makedirs(self, path, hide_dir_exists=True):
if hasattr(os, "umask"):
old_umask = os.umask(self.umask)
try:
os.makedirs(path)
except OSError, E:
# os.makedirs can suffer a race condition because it doesn't check
# that the directory doesn't exist at each step, nor does it
# catch errors. This lets 'directory exists' errors pass through,
# since they mean that as far as we're concerned, os.makedirs
# has 'worked'
if E.errno != 17 or not hide_dir_exists:
raise E
if hasattr(os, "umask"):
os.umask(old_umask)
def access(self, path, type='read'):
if self.platform == "jython":
if type == "read":
return self.file_module(path).canRead()
else:
return self.file_module(path).canWrite()
else:
if type =="read":
return os.access(path, os.R_OK)
else:
return os.access(path, os.W_OK)
def getKey (self, tile):
components = ( self.basedir,
tile.layer.name,
"%02d" % tile.z,
"%03d" % int(tile.x / 1000000),
"%03d" % (int(tile.x / 1000) % 1000),
"%03d" % (int(tile.x) % 1000),
"%03d" % int(tile.y / 1000000),
"%03d" % (int(tile.y / 1000) % 1000),
"%03d.%s" % (int(tile.y) % 1000, tile.layer.extension)
)
filename = os.path.join( *components )
return filename
def get (self, tile):
filename = self.getKey(tile)
if self.access(filename, 'read'):
if self.sendfile:
return filename
else:
tile.data = file(filename, "rb").read()
return tile.data
else:
return None
def set (self, tile, data):
if self.readonly: return data
filename = self.getKey(tile)
dirname = os.path.dirname(filename)
if not self.access(dirname, 'write'):
self.makedirs(dirname)
tmpfile = filename + ".%d.tmp" % os.getpid()
if hasattr(os, "umask"):
old_umask = os.umask(self.umask)
output = file(tmpfile, "wb")
output.write(data)
output.close()
if hasattr(os, "umask"):
os.umask( old_umask );
try:
os.rename(tmpfile, filename)
except OSError:
os.unlink(filename)
os.rename(tmpfile, filename)
tile.data = data
return data
def delete (self, tile):
filename = self.getKey(tile)
if self.access(filename, 'read'):
os.unlink(filename)
def attemptLock (self, tile):
name = self.getLockName(tile)
try:
self.makedirs(name, hide_dir_exists=False)
return True
except OSError:
pass
try:
st = os.stat(name)
if st.st_ctime + self.stale < time.time():
warnings.warn("removing stale lock %s" % name)
# remove stale lock
self.unlock(tile)
self.makedirs(name)
return True
except OSError:
pass
return False
def unlock (self, tile):
name = self.getLockName(tile)
try:
os.rmdir(name)
except OSError, E:
print >>sys.stderr, "unlock %s failed: %s" % (name, str(E))
tilecache-2.11/TileCache/Caches/PaxHeader/GoogleDisk.py 000644 777777 777777 00000000210 11456032272 024562 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311429
18 SCHILY.nlink=1
tilecache-2.11/TileCache/Caches/GoogleDisk.py 000644 473017214730172100000003017 11456032272 022757 0 ustar 00christos christos 000000 000000 # BSD Licensed, Copyright (c) 2008-2010 TileCache Contributors
"""
Provides a subclass of Disk Cache which saves in a simple z/x/y.extension, with
Y=0 being the top of the map, and heading down. This tile layout makes for
generation of tiles that is friendly to Google/OSM, and the opposite of TMS.
This is useful for pre-generating tiles for Google Maps which are going to be
used offline. This allows one to use TileCache in a gdal2tiles-like setup,
using the cache to write out a directory which can be used in other places.
Note that ext3 (a common Linux filesystem) will not support more than 32000
files in a directory, so if you plan to store a whole world at z15 or greater,
you should not use this cache class. (The Disk.py file is designed for this use
case.)
>>> from TileCache.Layer import Layer, Tile
>>> l = Layer("test")
>>> t = Tile(l, 14, 18, 12)
>>> c = GoogleDisk("/tmp/tilecache")
>>> c.getKey(t)
'/tmp/tilecache/test/12/14/4077.png'
"""
from TileCache.Cache import Cache
from TileCache.Caches.Disk import Disk
import os
class GoogleDisk(Disk):
def getKey (self, tile):
grid = tile.layer.grid(tile.z)
components = ( self.basedir,
tile.layer.name,
"%s" % int(tile.z),
"%s" % int(tile.x),
"%s.%s" % (int(grid[1] - 1 - tile.y), tile.layer.extension)
)
filename = os.path.join( *components )
return filename
if __name__ == "__main__":
import doctest
doctest.testmod()
tilecache-2.11/TileCache/Caches/PaxHeader/MBTiles.py 000644 777777 777777 00000000210 11454752000 024026 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311423
18 SCHILY.nlink=1
tilecache-2.11/TileCache/Caches/MBTiles.py 000644 473017214730172100000001755 11454752000 022232 0 ustar 00christos christos 000000 000000 # A minimal implementation of an MBTiles-formatted SQLite database
# cache access mechanism. (No writing, only reading.)
# See:
# http://mapbox.com/tools/mbtiles
# for more information on the mbtiles format; it is essentially a single
# table in a sqlite database with 4 columns:
# * tile_column
# * tile_row
# * zoom_level
# * tile_data
from TileCache.Cache import Cache
import os
import sqlite3
class MBTiles (Cache):
def __init__ (self, base = None, ext = None, umask = '002', **kwargs):
Cache.__init__(self, **kwargs)
self.basedir = base
self.ext = ext
def get (self, tile):
db = sqlite3.connect("%s.%s" % (os.path.join(self.basedir, tile.layer.name), self.ext))
c = db.cursor()
c.execute("select tile_data from tiles where tile_column=? and tile_row=? and zoom_level=?", (tile.x, tile.y, tile.z))
res = c.fetchone()
if res:
tile.data = str(res[0])
return tile.data
return None
tilecache-2.11/TileCache/Caches/PaxHeader/Memcached.py 000644 777777 777777 00000000210 11456032102 024371 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311428
18 SCHILY.nlink=1
tilecache-2.11/TileCache/Caches/Memcached.py 000644 473017214730172100000002161 11456032102 022565 0 ustar 00christos christos 000000 000000 # BSD Licensed, Copyright (c) 2006-2010 TileCache Contributors
from TileCache.Cache import Cache
import time
class Memcached(Cache):
def __init__ (self, servers = ['127.0.0.1:11211'], **kwargs):
Cache.__init__(self, **kwargs)
import memcache
if type(servers) is str: servers = map(str.strip, servers.split(","))
self.cache = memcache.Client(servers, debug=0)
def getKey(self, tile):
return "/".join(map(str, [tile.layer.name, tile.x, tile.y, tile.z]))
def get(self, tile):
key = self.getKey(tile)
tile.data = self.cache.get(key)
return tile.data
def set(self, tile, data):
if self.readonly: return data
key = self.getKey(tile)
self.cache.set(key, data)
return data
def delete(self, tile):
key = self.getKey(tile)
self.cache.delete(key)
def attemptLock (self, tile):
return self.cache.add( self.getLockName(tile), "0",
time.time() + self.timeout)
def unlock (self, tile):
self.cache.delete( self.getLockName(tile) )
tilecache-2.11/TileCache/Caches/PaxHeader/S3.py 000644 777777 777777 00000000210 10736373331 023024 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311427
18 SCHILY.nlink=1
tilecache-2.11/TileCache/Caches/S3.py 000644 473017214730172100000051653 10736373331 021232 0 ustar 00christos christos 000000 000000 # This code is downloaded as part of the "Amazon S3 Library for REST in Python"
# http://developer.amazonwebservices.com/connect/entry.jspa?externalID=134&categoryID=47
# It is taken verbatim from that download.
# This software code is made available "AS IS" without warranties of any
# kind. You may copy, display, modify and redistribute the software
# code either by itself or as incorporated into your code; provided that
# you do not remove any proprietary notices. Your use of this software
# code is at your own risk and you waive any claim against Amazon
# Digital Services, Inc. or its affiliates with respect to your use of
# this software code. (c) 2006-2008 Amazon Digital Services, Inc. or its
# affiliates.
import base64
import hmac
import httplib
import re
import sha
import sys
import time
import urllib
import urlparse
import xml.sax
DEFAULT_HOST = 's3.amazonaws.com'
PORTS_BY_SECURITY = { True: 443, False: 80 }
METADATA_PREFIX = 'x-amz-meta-'
AMAZON_HEADER_PREFIX = 'x-amz-'
# generates the aws canonical string for the given parameters
def canonical_string(method, bucket="", key="", query_args={}, headers={}, expires=None):
interesting_headers = {}
for header_key in headers:
lk = header_key.lower()
if lk in ['content-md5', 'content-type', 'date'] or lk.startswith(AMAZON_HEADER_PREFIX):
interesting_headers[lk] = headers[header_key].strip()
# these keys get empty strings if they don't exist
if not interesting_headers.has_key('content-type'):
interesting_headers['content-type'] = ''
if not interesting_headers.has_key('content-md5'):
interesting_headers['content-md5'] = ''
# just in case someone used this. it's not necessary in this lib.
if interesting_headers.has_key('x-amz-date'):
interesting_headers['date'] = ''
# if you're using expires for query string auth, then it trumps date
# (and x-amz-date)
if expires:
interesting_headers['date'] = str(expires)
sorted_header_keys = interesting_headers.keys()
sorted_header_keys.sort()
buf = "%s\n" % method
for header_key in sorted_header_keys:
if header_key.startswith(AMAZON_HEADER_PREFIX):
buf += "%s:%s\n" % (header_key, interesting_headers[header_key])
else:
buf += "%s\n" % interesting_headers[header_key]
# append the bucket if it exists
if bucket != "":
buf += "/%s" % bucket
# add the key. even if it doesn't exist, add the slash
buf += "/%s" % urllib.quote_plus(key)
# handle special query string arguments
if query_args.has_key("acl"):
buf += "?acl"
elif query_args.has_key("torrent"):
buf += "?torrent"
elif query_args.has_key("logging"):
buf += "?logging"
elif query_args.has_key("location"):
buf += "?location"
return buf
# computes the base64'ed hmac-sha hash of the canonical string and the secret
# access key, optionally urlencoding the result
def encode(aws_secret_access_key, str, urlencode=False):
b64_hmac = base64.encodestring(hmac.new(aws_secret_access_key, str, sha).digest()).strip()
if urlencode:
return urllib.quote_plus(b64_hmac)
else:
return b64_hmac
def merge_meta(headers, metadata):
final_headers = headers.copy()
for k in metadata.keys():
final_headers[METADATA_PREFIX + k] = metadata[k]
return final_headers
# builds the query arg string
def query_args_hash_to_string(query_args):
query_string = ""
pairs = []
for k, v in query_args.items():
piece = k
if v != None:
piece += "=%s" % urllib.quote_plus(str(v))
pairs.append(piece)
return '&'.join(pairs)
class CallingFormat:
PATH = 1
SUBDOMAIN = 2
VANITY = 3
def build_url_base(protocol, server, port, bucket, calling_format):
url_base = '%s://' % protocol
if bucket == '':
url_base += server
elif calling_format == CallingFormat.SUBDOMAIN:
url_base += "%s.%s" % (bucket, server)
elif calling_format == CallingFormat.VANITY:
url_base += bucket
else:
url_base += server
url_base += ":%s" % port
if (bucket != '') and (calling_format == CallingFormat.PATH):
url_base += "/%s" % bucket
return url_base
build_url_base = staticmethod(build_url_base)
class Location:
DEFAULT = None
EU = 'EU'
class AWSAuthConnection:
def __init__(self, aws_access_key_id, aws_secret_access_key, is_secure=True,
server=DEFAULT_HOST, port=None, calling_format=CallingFormat.SUBDOMAIN):
if not port:
port = PORTS_BY_SECURITY[is_secure]
self.aws_access_key_id = aws_access_key_id
self.aws_secret_access_key = aws_secret_access_key
self.is_secure = is_secure
self.server = server
self.port = port
self.calling_format = calling_format
def create_bucket(self, bucket, headers={}):
return Response(self._make_request('PUT', bucket, '', {}, headers))
def create_located_bucket(self, bucket, location=Location.DEFAULT, headers={}):
if location == Location.DEFAULT:
body = ""
else:
body = "" + \
location + \
""
return Response(self._make_request('PUT', bucket, '', {}, headers, body))
def check_bucket_exists(self, bucket):
return self._make_request('HEAD', bucket, '', {}, {})
def list_bucket(self, bucket, options={}, headers={}):
return ListBucketResponse(self._make_request('GET', bucket, '', options, headers))
def delete_bucket(self, bucket, headers={}):
return Response(self._make_request('DELETE', bucket, '', {}, headers))
def put(self, bucket, key, object, headers={}):
if not isinstance(object, S3Object):
object = S3Object(object)
return Response(
self._make_request(
'PUT',
bucket,
key,
{},
headers,
object.data,
object.metadata))
def get(self, bucket, key, headers={}):
return GetResponse(
self._make_request('GET', bucket, key, {}, headers))
def delete(self, bucket, key, headers={}):
return Response(
self._make_request('DELETE', bucket, key, {}, headers))
def get_bucket_logging(self, bucket, headers={}):
return GetResponse(self._make_request('GET', bucket, '', { 'logging': None }, headers))
def put_bucket_logging(self, bucket, logging_xml_doc, headers={}):
return Response(self._make_request('PUT', bucket, '', { 'logging': None }, headers, logging_xml_doc))
def get_bucket_acl(self, bucket, headers={}):
return self.get_acl(bucket, '', headers)
def get_acl(self, bucket, key, headers={}):
return GetResponse(
self._make_request('GET', bucket, key, { 'acl': None }, headers))
def put_bucket_acl(self, bucket, acl_xml_document, headers={}):
return self.put_acl(bucket, '', acl_xml_document, headers)
def put_acl(self, bucket, key, acl_xml_document, headers={}):
return Response(
self._make_request(
'PUT',
bucket,
key,
{ 'acl': None },
headers,
acl_xml_document))
def list_all_my_buckets(self, headers={}):
return ListAllMyBucketsResponse(self._make_request('GET', '', '', {}, headers))
def get_bucket_location(self, bucket):
return LocationResponse(self._make_request('GET', bucket, '', {'location' : None}))
# end public methods
def _make_request(self, method, bucket='', key='', query_args={}, headers={}, data='', metadata={}):
server = ''
if bucket == '':
server = self.server
elif self.calling_format == CallingFormat.SUBDOMAIN:
server = "%s.%s" % (bucket, self.server)
elif self.calling_format == CallingFormat.VANITY:
server = bucket
else:
server = self.server
path = ''
if (bucket != '') and (self.calling_format == CallingFormat.PATH):
path += "/%s" % bucket
# add the slash after the bucket regardless
# the key will be appended if it is non-empty
path += "/%s" % urllib.quote_plus(key)
# build the path_argument string
# add the ? in all cases since
# signature and credentials follow path args
if len(query_args):
path += "?" + query_args_hash_to_string(query_args)
is_secure = self.is_secure
host = "%s:%d" % (server, self.port)
while True:
if (is_secure):
connection = httplib.HTTPSConnection(host)
else:
connection = httplib.HTTPConnection(host)
final_headers = merge_meta(headers, metadata);
# add auth header
self._add_aws_auth_header(final_headers, method, bucket, key, query_args)
connection.request(method, path, data, final_headers)
resp = connection.getresponse()
if resp.status < 300 or resp.status >= 400:
return resp
# handle redirect
location = resp.getheader('location')
if not location:
return resp
# (close connection)
resp.read()
scheme, host, path, params, query, fragment \
= urlparse.urlparse(location)
if scheme == "http": is_secure = True
elif scheme == "https": is_secure = False
else: raise invalidURL("Not http/https: " + location)
if query: path += "?" + query
# retry with redirect
def _add_aws_auth_header(self, headers, method, bucket, key, query_args):
if not headers.has_key('Date'):
headers['Date'] = time.strftime("%a, %d %b %Y %X GMT", time.gmtime())
c_string = canonical_string(method, bucket, key, query_args, headers)
headers['Authorization'] = \
"AWS %s:%s" % (self.aws_access_key_id, encode(self.aws_secret_access_key, c_string))
class QueryStringAuthGenerator:
# by default, expire in 1 minute
DEFAULT_EXPIRES_IN = 60
def __init__(self, aws_access_key_id, aws_secret_access_key, is_secure=True,
server=DEFAULT_HOST, port=None, calling_format=CallingFormat.SUBDOMAIN):
if not port:
port = PORTS_BY_SECURITY[is_secure]
self.aws_access_key_id = aws_access_key_id
self.aws_secret_access_key = aws_secret_access_key
if (is_secure):
self.protocol = 'https'
else:
self.protocol = 'http'
self.is_secure = is_secure
self.server = server
self.port = port
self.calling_format = calling_format
self.__expires_in = QueryStringAuthGenerator.DEFAULT_EXPIRES_IN
self.__expires = None
# for backwards compatibility with older versions
self.server_name = "%s:%s" % (self.server, self.port)
def set_expires_in(self, expires_in):
self.__expires_in = expires_in
self.__expires = None
def set_expires(self, expires):
self.__expires = expires
self.__expires_in = None
def create_bucket(self, bucket, headers={}):
return self.generate_url('PUT', bucket, '', {}, headers)
def list_bucket(self, bucket, options={}, headers={}):
return self.generate_url('GET', bucket, '', options, headers)
def delete_bucket(self, bucket, headers={}):
return self.generate_url('DELETE', bucket, '', {}, headers)
def put(self, bucket, key, object, headers={}):
if not isinstance(object, S3Object):
object = S3Object(object)
return self.generate_url(
'PUT',
bucket,
key,
{},
merge_meta(headers, object.metadata))
def get(self, bucket, key, headers={}):
return self.generate_url('GET', bucket, key, {}, headers)
def delete(self, bucket, key, headers={}):
return self.generate_url('DELETE', bucket, key, {}, headers)
def get_bucket_logging(self, bucket, headers={}):
return self.generate_url('GET', bucket, '', { 'logging': None }, headers)
def put_bucket_logging(self, bucket, logging_xml_doc, headers={}):
return self.generate_url('PUT', bucket, '', { 'logging': None }, headers)
def get_bucket_acl(self, bucket, headers={}):
return self.get_acl(bucket, '', headers)
def get_acl(self, bucket, key='', headers={}):
return self.generate_url('GET', bucket, key, { 'acl': None }, headers)
def put_bucket_acl(self, bucket, acl_xml_document, headers={}):
return self.put_acl(bucket, '', acl_xml_document, headers)
# don't really care what the doc is here.
def put_acl(self, bucket, key, acl_xml_document, headers={}):
return self.generate_url('PUT', bucket, key, { 'acl': None }, headers)
def list_all_my_buckets(self, headers={}):
return self.generate_url('GET', '', '', {}, headers)
def make_bare_url(self, bucket, key=''):
full_url = self.generate_url(self, bucket, key)
return full_url[:full_url.index('?')]
def generate_url(self, method, bucket='', key='', query_args={}, headers={}):
expires = 0
if self.__expires_in != None:
expires = int(time.time() + self.__expires_in)
elif self.__expires != None:
expires = int(self.__expires)
else:
raise "Invalid expires state"
canonical_str = canonical_string(method, bucket, key, query_args, headers, expires)
encoded_canonical = encode(self.aws_secret_access_key, canonical_str)
url = CallingFormat.build_url_base(self.protocol, self.server, self.port, bucket, self.calling_format)
url += "/%s" % urllib.quote_plus(key)
query_args['Signature'] = encoded_canonical
query_args['Expires'] = expires
query_args['AWSAccessKeyId'] = self.aws_access_key_id
url += "?%s" % query_args_hash_to_string(query_args)
return url
class S3Object:
def __init__(self, data, metadata={}):
self.data = data
self.metadata = metadata
class Owner:
def __init__(self, id='', display_name=''):
self.id = id
self.display_name = display_name
class ListEntry:
def __init__(self, key='', last_modified=None, etag='', size=0, storage_class='', owner=None):
self.key = key
self.last_modified = last_modified
self.etag = etag
self.size = size
self.storage_class = storage_class
self.owner = owner
class CommonPrefixEntry:
def __init(self, prefix=''):
self.prefix = prefix
class Bucket:
def __init__(self, name='', creation_date=''):
self.name = name
self.creation_date = creation_date
class Response:
def __init__(self, http_response):
self.http_response = http_response
# you have to do this read, even if you don't expect a body.
# otherwise, the next request fails.
self.body = http_response.read()
if http_response.status >= 300 and self.body:
self.message = self.body
else:
self.message = "%03d %s" % (http_response.status, http_response.reason)
class ListBucketResponse(Response):
def __init__(self, http_response):
Response.__init__(self, http_response)
if http_response.status < 300:
handler = ListBucketHandler()
xml.sax.parseString(self.body, handler)
self.entries = handler.entries
self.common_prefixes = handler.common_prefixes
self.name = handler.name
self.marker = handler.marker
self.prefix = handler.prefix
self.is_truncated = handler.is_truncated
self.delimiter = handler.delimiter
self.max_keys = handler.max_keys
self.next_marker = handler.next_marker
else:
self.entries = []
class ListAllMyBucketsResponse(Response):
def __init__(self, http_response):
Response.__init__(self, http_response)
if http_response.status < 300:
handler = ListAllMyBucketsHandler()
xml.sax.parseString(self.body, handler)
self.entries = handler.entries
else:
self.entries = []
class GetResponse(Response):
def __init__(self, http_response):
Response.__init__(self, http_response)
response_headers = http_response.msg # older pythons don't have getheaders
metadata = self.get_aws_metadata(response_headers)
self.object = S3Object(self.body, metadata)
def get_aws_metadata(self, headers):
metadata = {}
for hkey in headers.keys():
if hkey.lower().startswith(METADATA_PREFIX):
metadata[hkey[len(METADATA_PREFIX):]] = headers[hkey]
del headers[hkey]
return metadata
class LocationResponse(Response):
def __init__(self, http_response):
Response.__init__(self, http_response)
if http_response.status < 300:
handler = LocationHandler()
xml.sax.parseString(self.body, handler)
self.location = handler.location
class ListBucketHandler(xml.sax.ContentHandler):
def __init__(self):
self.entries = []
self.curr_entry = None
self.curr_text = ''
self.common_prefixes = []
self.curr_common_prefix = None
self.name = ''
self.marker = ''
self.prefix = ''
self.is_truncated = False
self.delimiter = ''
self.max_keys = 0
self.next_marker = ''
self.is_echoed_prefix_set = False
def startElement(self, name, attrs):
if name == 'Contents':
self.curr_entry = ListEntry()
elif name == 'Owner':
self.curr_entry.owner = Owner()
elif name == 'CommonPrefixes':
self.curr_common_prefix = CommonPrefixEntry()
def endElement(self, name):
if name == 'Contents':
self.entries.append(self.curr_entry)
elif name == 'CommonPrefixes':
self.common_prefixes.append(self.curr_common_prefix)
elif name == 'Key':
self.curr_entry.key = self.curr_text
elif name == 'LastModified':
self.curr_entry.last_modified = self.curr_text
elif name == 'ETag':
self.curr_entry.etag = self.curr_text
elif name == 'Size':
self.curr_entry.size = int(self.curr_text)
elif name == 'ID':
self.curr_entry.owner.id = self.curr_text
elif name == 'DisplayName':
self.curr_entry.owner.display_name = self.curr_text
elif name == 'StorageClass':
self.curr_entry.storage_class = self.curr_text
elif name == 'Name':
self.name = self.curr_text
elif name == 'Prefix' and self.is_echoed_prefix_set:
self.curr_common_prefix.prefix = self.curr_text
elif name == 'Prefix':
self.prefix = self.curr_text
self.is_echoed_prefix_set = True
elif name == 'Marker':
self.marker = self.curr_text
elif name == 'IsTruncated':
self.is_truncated = self.curr_text == 'true'
elif name == 'Delimiter':
self.delimiter = self.curr_text
elif name == 'MaxKeys':
self.max_keys = int(self.curr_text)
elif name == 'NextMarker':
self.next_marker = self.curr_text
self.curr_text = ''
def characters(self, content):
self.curr_text += content
class ListAllMyBucketsHandler(xml.sax.ContentHandler):
def __init__(self):
self.entries = []
self.curr_entry = None
self.curr_text = ''
def startElement(self, name, attrs):
if name == 'Bucket':
self.curr_entry = Bucket()
def endElement(self, name):
if name == 'Name':
self.curr_entry.name = self.curr_text
elif name == 'CreationDate':
self.curr_entry.creation_date = self.curr_text
elif name == 'Bucket':
self.entries.append(self.curr_entry)
def characters(self, content):
self.curr_text = content
class LocationHandler(xml.sax.ContentHandler):
def __init__(self):
self.location = None
self.state = 'init'
def startElement(self, name, attrs):
if self.state == 'init':
if name == 'LocationConstraint':
self.state = 'tag_location'
self.location = ''
else: self.state = 'bad'
else: self.state = 'bad'
def endElement(self, name):
if self.state == 'tag_location' and name == 'LocationConstraint':
self.state = 'done'
else: self.state = 'bad'
def characters(self, content):
if self.state == 'tag_location':
self.location += content
tilecache-2.11/TileCache/Caches/PaxHeader/Test.py 000644 777777 777777 00000000210 11010637741 023450 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311424
18 SCHILY.nlink=1
tilecache-2.11/TileCache/Caches/Test.py 000644 473017214730172100000001062 11010637741 021643 0 ustar 00christos christos 000000 000000 from TileCache.Cache import Cache
class Test(Cache):
"""
A Cache class which does not cache anything: useful for
testing during development, or any other setup where
TileCache should not cache data. In general, using this
with metatiles is very slow, and not recommended.
"""
def get(self, tile):
return None
def set(self, tile, data):
return data
def getKey(self, tile):
return "abc"
def attemptLock(self, tile):
return True
def unlock(self, tile):
pass
tilecache-2.11/tests/PaxHeader/__init__.py 000644 777777 777777 00000000210 11456027207 022427 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311437
18 SCHILY.nlink=1
tilecache-2.11/tests/__init__.py 000644 473017214730172100000000040 11456027207 020615 0 ustar 00christos christos 000000 000000 from tests import run_doc_tests
tilecache-2.11/tests/PaxHeader/HACKING.swarm.txt 000644 777777 777777 00000000210 11456031665 023256 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311439
18 SCHILY.nlink=1
tilecache-2.11/tests/HACKING.swarm.txt 000644 473017214730172100000002616 11456031665 021457 0 ustar 00christos christos 000000 000000 >>> from TileCache.Swarm import Message
>>> from TileCache.Layer import Layer, Tile
>>> from sha import sha
>>> layers = { "Some Layer": Layer("Some Layer") }
>>> key = sha("test").digest()
>>> msg1 = Message("PING", key, 123456)
>>> msg1.type == "PING"
True
>>> msg1.key == key
True
>>> msg1.seq_id == 123456
True
>>> thunk = msg1.freeze()
>>> thunk
'\xa9J\x8f\xe5\xcc\xb1\x9b\xa6\x1cL\x08s\xd3\x91\xe9\x87\x98/\xbb\xd3\x00\x01\xe2@\x00\x00\x00\x00'
>>> msg2 = Message.thaw(thunk, layers)
>>> msg2.key == msg1.key
True
>>> msg2.seq_id == msg1.seq_id
True
>>> msg2.type == msg1.type
True
>>> tile = Tile( layers["Some Layer"], 8, 16, 32 )
>>> msg1 = Message( "GET", key, 54321, tile )
>>> msg1.tile == tile
True
>>> thunk = msg1.freeze()
>>> thunk
'\xa9J\x8f\xe5\xcc\xb1\x9b\xa6\x1cL\x08s\xd3\x91\xe9\x87\x98/\xbb\xd3\x00\x00\xd41\x00\x02\x00\x00\nSome Layer\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x08\x00\x00\x00\x10'
>>> msg2 = Message.thaw( thunk, layers )
>>> msg2.type == "GET"
True
>>> msg1.tile.layer == msg2.tile.layer
True
>>> msg1.tile.x == msg2.tile.x
True
>>> msg1.tile.y == msg2.tile.y
True
>>> msg1.tile.z == msg2.tile.z
True
>>> tile.data = "here is some data"
>>> msg1 = Message( "PUT", key, 101101, tile )
>>> msg2 = Message.thaw( msg1.freeze(), layers )
>>> msg2.type == "PUT"
True
>>> msg1.tile.data == msg2.tile.data
True
tilecache-2.11/tests/PaxHeader/HACKING.txt 000644 777777 777777 00000000210 11007051140 022104 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311436
18 SCHILY.nlink=1
tilecache-2.11/tests/HACKING.txt 000644 473017214730172100000006543 11007051140 020310 0 ustar 00christos christos 000000 000000 Handlers
========
There are two handlers for requests: a cgiHandler and a modPythonHandler.
These two handlers allow the TileCache tool to be set up under CGI or
mod_python. A handler accepts a Service as an argument.
Services
========
The service request does dispatching to a Request handler, passing on
the neccesary information to the parser and renderers of the request.
The Service contains information about the cache and layers that are
supported, and uses methods on the Request to generate data which
is returned to the handlers.
The Service makes a heuristic determination as to which Request handler
is appropriate.
Requests
========
Request objects define a single 'parse' function, which is used to
accept PATH_INFO and QUERY_STRING data from the Service, and convert
it to tiles. The Tile is then passed to the Layer, which knows how to
return image data for a specific tile object.
Cache
=====
Cache objects are simple interfaces to cache storage mechanisms. They
support three functions: get, set, and delete. These three functions
are used to control the cache
* get accepts a tile object, and is expected to return image data
or 'None'
* set accepts a tile object and data, and is expected to store this
data.
* delete accepts a tile object, and should cause future gets for
that tile to return None (until set again)
Layers
======
You can create a layer:
>>> from TileCache.Layer import Layer
>>> l = Layer("Test")
>>> type(l)
There are a number of defaults on the layer. These defaults conform to the
unprojected global profile described by the WMS Tiling Client Recommendations:
>>> l.name
'Test'
>>> l.layers
'Test'
>>> l.bbox
(-180, -90, 180, 90)
>>> l.resolutions[0]
0.703125
>>> l.srs
'EPSG:4326'
>>> l.size
(256, 256)
By default, the Layer supports up to 20 resolutions, or 'zoom levels'.
>>> len(l.resolutions)
20
However, you can create a layer which overrides these parameters:
>>> l = Layer("Test 2", layers="foo,bar,baz", levels=10)
>>> l.layers
'foo,bar,baz'
>>> len(l.resolutions)
10
There are a number of subclasses of layer, which add additional properties
for the layers. Subclasses of layer define a rendering mechanism through which
tiles are actually created.
To create a subclass of layer, you must define a 'render' function.
Render is passed a 'self' object of the layer, and a Tile object, described
later in this document. Refer to the existing layers for examples of how to
create a subclass of layer.
Layers have the ability to get a tile cell based on a bounding box: this
calculation can be exact or it can round to the nearest cell. This is used
internally when creating tiles, but can also be used directly by calling
the layer with a bounding box.
>>> cell = l.getCell((-157.5, -45.0, -135.0, -22.5))
>>> cell
(1, 2, 3)
This fails, because it's not an exact tile:
>>> import TileCache
>>> l.debug = False
>>> try:
... cell = l.getCell((-180, -90.0, 4, 75))
... except TileCache.TileCacheException:
... print "Failed"
Failed
Tiles
=====
Tiles store information about where in the world you are requesting, based
on the layer and x,y,z information. Tiles give access to X, Y, and Z value, as
well as a bounds() and bbox() method.
>>> from TileCache.Layer import Tile
>>> t = Tile(l, x=1, y=2, z=3)
>>> t.bbox()
'-157.5,-45.0,-135.0,-22.5'
>>> t.bounds()
(-157.5, -45.0, -135.0, -22.5)
tilecache-2.11/tests/PaxHeader/Service.txt 000644 777777 777777 00000000210 11456031665 022462 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311440
18 SCHILY.nlink=1
tilecache-2.11/tests/Service.txt 000644 473017214730172100000010273 11456031665 020661 0 ustar 00christos christos 000000 000000 The Service is the core component of the TileCache Server: various services
(wsgi, cgi, mod_python) feed into it. You can see the properties::
>>> import TileCache.Service
>>> filter(lambda x: not x.startswith("_"), dir(TileCache.Service))
['cache', 'config', 'dispatchRequest', 'expireTile', 'files', 'generate_crossdomain_xml', 'layers', 'load', 'loadFromSection', 'metadata', 'renderTile', 'tilecache_options']
Or you can create one. In general, this is generated via the config file,
but you can build one manually as well::
>>> from TileCache.Caches.Disk import Disk
>>> from TileCache.Layer import Layer, Tile
>>> l = Layer("basic", debug=False)
>>> t = Tile(l, 0, 0, 0)
>>> service = TileCache.Service(Disk("/tmp/tilecache"), {"layer": l})
>>> service # doctest: +ELLIPSIS
The Service dispatchRequest method is what actually generates the tiles. It calls
out to the layer's renderTile method. On the base Layer class, nothing is
returned: all renderTile implementation is done by subclasses. As a result,
rendering the tile fails on this layer::
>>> try:
... tile_data = service.dispatchRequest({}, path_info="/1.0.0/layer/0/0/0.png")
... except Exception, E:
... str(E)
'Zero length data returned from layer.'
KML SuperOverlays can be generated as an alternative output to the TMS-style
requests: simply change the image format to ".kml".
>>> kml = service.dispatchRequest({}, path_info="/1.0.0/layer/0/0/0.kml")
>>> kml[0]
'application/vnd.google-earth.kml+xml'
>>> kml[1]
'\n\n\n \n \n \n 256512\n \n \n 90.0-90.0\n 0.0-180.0\n \n \n \n 0\n \n http://example.com//1.0.0/basic/0/0/0\n \n \n 90.0-90.0\n 0.0-180.0\n \n \n \n tile\n \n \n 256-1\n \n \n 0.0-90.0\n -90.0-180.0\n \n \n \n http://example.com//1.0.0/basic/1/0/0.kml\n onRegion\n \n \n\n tile\n \n \n 256-1\n \n \n 0.0-90.0\n 0.0-90.0\n \n \n \n http://example.com//1.0.0/basic/1/1/0.kml\n onRegion\n \n \n\n tile\n \n \n 256-1\n \n \n 90.00.0\n 0.0-90.0\n \n \n \n http://example.com//1.0.0/basic/1/1/1.kml\n onRegion\n \n \n\n tile\n \n \n 256-1\n \n \n 90.00.0\n -90.0-180.0\n \n \n \n http://example.com//1.0.0/basic/1/0/1.kml\n onRegion\n \n \n \n'
tilecache-2.11/tests/PaxHeader/tests.py 000644 777777 777777 00000000210 10733210232 022017 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311438
18 SCHILY.nlink=1
tilecache-2.11/tests/tests.py 000644 473017214730172100000002044 10733210232 020213 0 ustar 00christos christos 000000 000000 # stolen from shapely
# http://trac.gispython.org/projects/PCL/browser/Shapely/trunk/tests/test_doctests.py
# Copyright (c) 2007, Sean C. Gillies
import doctest
import unittest
import glob
import os
optionflags = (doctest.NORMALIZE_WHITESPACE |
doctest.ELLIPSIS)
def list_doctests():
return [filename
for filename
in glob.glob(os.path.join(os.path.dirname(__file__), '*.txt'))]
def open_file(filename, mode='r'):
"""Helper function to open files from within the tests package."""
return open(os.path.join(os.path.dirname(__file__), filename), mode)
def setUp(test):
test.globs.update(dict(
open_file = open_file,
))
def run_doc_tests():
return unittest.TestSuite(
[doctest.DocFileSuite(os.path.basename(filename),
optionflags=optionflags,
setUp=setUp)
for filename
in list_doctests()])
if __name__ == "__main__":
runner = unittest.TextTestRunner()
runner.run(run_doc_tests())
tilecache-2.11/docs/PaxHeader/_static 000755 777777 777777 00000000210 11456036475 021467 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142717
24 SCHILY.dev=234881029
22 SCHILY.ino=3311451
18 SCHILY.nlink=3
tilecache-2.11/docs/_static/ 000755 473017214730172100000000000 11456036475 017735 5 ustar 00christos christos 000000 000000 tilecache-2.11/docs/PaxHeader/_templates 000755 777777 777777 00000000210 11456036476 022177 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142718
20 atime=1287142718
24 SCHILY.dev=234881029
22 SCHILY.ino=3311459
18 SCHILY.nlink=2
tilecache-2.11/docs/_templates/ 000755 473017214730172100000000000 11456036476 020445 5 ustar 00christos christos 000000 000000 tilecache-2.11/docs/PaxHeader/Caches.txt 000644 777777 777777 00000000210 11454752353 022040 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142718
24 SCHILY.dev=234881029
22 SCHILY.ino=3311449
18 SCHILY.nlink=1
tilecache-2.11/docs/Caches.txt 000644 473017214730172100000006333 11454752353 020241 0 ustar 00christos christos 000000 000000 TileCache Caches
================
TileCache offers access to a number of different caches. These caches are used
to store tiles.
Disk
----
Example Configuration::
[cache]
type=Disk
base=/var/lib/tilecache
umask=002
sendfile=yes
expire=3600
Dependencies: None
The sendfile=yes option instructs TileCache to send an X-SendFile header to
the web server rather than the contents of the image.
See http://blog.lighttpd.net/articles/2006/07/02/x-sendfile and
http://tn123.ath.cx/mod_xsendfile/
GoogleDisk
----
Example Configuration::
[cache]
type=GoogleDisk
base=/var/lib/tilecache
Dependencies: None
Note: A simple subclass of the Disk cache, this switches the Y tile ordering
on the disk, so Google Maps users can easily access tiles directly (e.g.
bypassing tilecache.py, if all tiles have been pre-rendered) with a simple
CustomTileUrl function.
Memcached
---------
Example configuration::
[cache]
type=Memcached
servers=127.0.0.1:11211
Dependencies:
* memcache Python module must be installed on your system path.
http://code.sixapart.com/svn/memcached/trunk/api/python/memcache.py
Amazon S3
---------
Example configuration::
[cache]
type=AWSS3
access_key=833833ABC88838
secret_access_key=8234abyi3kdjby8so8idu
use_tms_paths=true
The use_tms_paths will make the files more accessible to other clients,
though at this time, ACLs are not set on the TMS structure to make them
available publicly.
The use_tms_paths can also be set to "flipped": if so, it will result in
'flipped' TMS, with typical paths like:
/1.0.0/9/82/63.png
But with 0 starting at the top of the map, instead of the bottom.
This cache can use one of two libraries:
Boto
____
Available from http://code.google.com/p/boto/, boto is a package that
wraps the Amazon APIs in a Pythonic wrapper. This is installable on
recent Debian-based distributions as python-boto. It can be installed
via easy_install from setuptools as well: simply easy_install boto.
The boto library is more complete, and is more likely to properly
handle error conditions than the Amazon Example Library.
Amazon Example Library
______________________
Amazon provides an example Python library. This library provides a simple
wrapper around the Amazon web services. The code is available from
http://developer.amazonwebservices.com/connect/entry.jspa?externalID=134&categoryID=47
You must download, unpack, and place the s3-example-libraries/python/S3.py
file on your PYTHONPATH/sys.path. The source distribution of TileCache
includes this file in the TileCache/Caches/S3.py file. (Packagers are
encouraged to remove this file from distributions and instead depend
on the boto library described above.)
MBTiles
-------
Simple read-only format for MBTiles sqlite databases. Name each database
according to the name of the layer, and place it inside your cache directory,
and provide an extension to your cache.
[cache]
type=MBTiles
base=./tiles
ext=db
For layer basic, this will attempt to open a sqlite3 database at
./tiles/basic.db .
See http://mapbox.com/tools/mbtiles for more details.
All Caches
----------
All Caches support the expire option.
The expire=n option instructs TileCache to send an Expires header, with the
date set 'n' seconds into the future.
tilecache-2.11/docs/PaxHeader/conf.py 000644 777777 777777 00000000210 11456032272 021401 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142718
20 atime=1287142718
24 SCHILY.dev=234881029
22 SCHILY.ino=3311457
18 SCHILY.nlink=1
tilecache-2.11/docs/conf.py 000644 473017214730172100000013460 11456032272 017601 0 ustar 00christos christos 000000 000000 # -*- coding: utf-8 -*-
#
# TileCache documentation build configuration file, created by
# sphinx-quickstart on Sat Dec 27 06:07:30 2008.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# The contents of this file are pickled, so don't put values in the namespace
# that aren't pickleable (module imports are okay, they're removed automatically).
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys, os
# If your extensions are in another directory, add it here. If the directory
# is relative to the documentation root, use os.path.abspath to make it
# absolute, like shown here.
#sys.path.append(os.path.abspath('.'))
# General configuration
# ---------------------
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = []
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.txt'
# The encoding of source files.
#source_encoding = 'utf-8'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'TileCache'
copyright = u'2008-2010, TileCache Project'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '2.11'
# The full version, including alpha/beta/rc tags.
release = '2.11'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of documents that shouldn't be included in the build.
#unused_docs = []
# List of directories, relative to source directory, that shouldn't be searched
# for source files.
exclude_trees = ['_build']
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# Options for HTML output
# -----------------------
# The style sheet to use for HTML and HTML Help pages. A file of that name
# must exist either in Sphinx' static/ path, or in one of the custom paths
# given in html_static_path.
html_style = 'default.css'
# The name for this set of Sphinx documents. If None, it defaults to
# " v documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_use_modindex = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, the reST sources are included in the HTML build as _sources/.
#html_copy_source = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = ''
# Output file base name for HTML help builder.
htmlhelp_basename = 'TileCachedoc'
# Options for LaTeX output
# ------------------------
# The paper size ('letter' or 'a4').
#latex_paper_size = 'letter'
# The font size ('10pt', '11pt' or '12pt').
#latex_font_size = '10pt'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, document class [howto/manual]).
latex_documents = [
('index', 'TileCache.tex', ur'TileCache Documentation',
ur'TileCache Project', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# Additional stuff for the LaTeX preamble.
#latex_preamble = ''
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_use_modindex = True
tilecache-2.11/docs/PaxHeader/CONTRIBUTORS.txt 000644 777777 777777 00000000210 11134764352 022604 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142718
20 atime=1287142718
24 SCHILY.dev=234881029
22 SCHILY.ino=3311454
18 SCHILY.nlink=1
tilecache-2.11/docs/CONTRIBUTORS.txt 000644 473017214730172100000000527 11134764352 021004 0 ustar 00christos christos 000000 000000 Contributors
------------
The following people have contributed to TileCache development:
| Tibor Arpas
| Howard Butler
| Schuyler Erle
| Emily Gouge
| Suki Hirata
| Hani Howari
| Andrew Hughes
| Eric Lemoine
| Steven Ottens
| Matthew Perry
| Bruce Rindahl
| Tim Schaub
| Christopher Schmidt
| Ehud Shabtai
| Dane Springmeyer
| Bill Woodall
tilecache-2.11/docs/PaxHeader/Example.py.txt 000755 777777 777777 00000000210 10743307472 022675 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142718
24 SCHILY.dev=234881029
22 SCHILY.ino=3311446
18 SCHILY.nlink=1
tilecache-2.11/docs/Example.py.txt 000755 473017214730172100000003403 10743307472 021071 0 ustar 00christos christos 000000 000000 #!/usr/bin/python
# This example code demonstrates how you can construct
# a custom service as an alternative to the config file.
# This allows you to, for example, determine what layers to
# load based on request parameters or something similar --
# the config file based loading technique is handy, but
# probably doesn't solve all problems.
from TileCache.Service import Service, modPythonHandler, cgiHandler
from TileCache.Caches.Disk import Disk
import TileCache.Layers.WMS as WMS
import TileCache.Layers.MapServer as MS
myService = Service (
Disk("/www/wms-c/cache"),
{
"basic" : MS.MapServer( "basic", "/www/wms-c/basic.map" ),
"satellite" : MS.MapServer( "satellite", "/www/wms-c/basic.map",
extension = "jpeg" ),
"cascade" : WMS.WMS( "basic", "http://labs.metacarta.com/wms/vmap0?",
extension = "jpeg" ),
"DRG" : WMS.WMS( "DRG", "http://terraservice.net/ogcmap.ashx?",
extension = "jpeg" ),
"OSM" : WMS.WMS( "roads",
"http://aesis.metacarta.com/cgi-bin/mapserv?FORMAT=png8&" +
"map=/home/crschmidt/osm.map&TRANSPARENT=TRUE&",
extension = "png" ),
"Boston" : WMS.WMS(
"border,water,openspace,roads,buildings,rapid_transit",
"http://nyc.freemap.in/cgi-bin/mapserv?" +
"map=/www/freemap.in/boston/map/gmaps.map&" ),
"hfoot" : WMS.WMS( "hfoot",
"http://beta.sedac.ciesin.columbia.edu/mapserver/wms/hfoot?",
levels = 20, extension = "jpeg")
}
)
def handler (req):
return modPythonHandler(req, myService)
if __name__ == '__main__':
cgiHandler(myService)
tilecache-2.11/docs/PaxHeader/examples 000755 777777 777777 00000000210 11456036476 021660 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142718
20 atime=1287142718
24 SCHILY.dev=234881029
22 SCHILY.ino=3311460
18 SCHILY.nlink=3
tilecache-2.11/docs/examples/ 000755 473017214730172100000000000 11456036476 020126 5 ustar 00christos christos 000000 000000 tilecache-2.11/docs/PaxHeader/EXAMPLES.txt 000644 777777 777777 00000000210 11125407126 022056 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142718
20 atime=1287142718
24 SCHILY.dev=234881029
22 SCHILY.ino=3311456
18 SCHILY.nlink=1
tilecache-2.11/docs/EXAMPLES.txt 000644 473017214730172100000002477 11125407126 020264 0 ustar 00christos christos 000000 000000 Layer Examples
==============
Some Example Layer Configurations::
[mario-8-4]
type=ImageLayer
file=/home/images/mario-8-4.gif
bbox=0,0,5889,224
filebounds=0,0,5889,224
maxresolution=16
[avalon]
type=GDAL
file=/home/images/avalon.jpg
bbox=0,0,4000,1870
[avalon]
type=ImageLayer
filebounds=-180,-88.759,180,88.759
file=/home/images/avalon.jpg
[basic]
type=MapServerLayer
layers=basic
mapfile=/home/tilecache/basic.map
debug=off
description=VMap0-based vector layer, styled by Schuyler Erle.
[DRG]
type=WMSLayer
layers=DRG
url=http://terraservice.net/ogcmap.ashx?
extension=jpeg
debug=off
[osm-map]
type=MapnikLayer
mapfile=/www/wms-c/osm.xml
[massgis]
type=ArcXML
url=http://maps.massgis.state.ma.us/servlet/com.esri.esrimap.Esrimap?ServiceName=coq2005hsde_with_roads&ClientVersion=4.0
layers=14
bbox=218337.16112593404,889611.9317974453,248183.9359890727,914312.7109945256
[massgis-reprojected]
type=ArcXML
url=http://maps.massgis.state.ma.us/servlet/com.esri.esrimap.Esrimap?ServiceName=coq2005hsde_with_roads&ClientVersion=4.0
projection=@/path/to/target_projection # Either a string, or if prefixed by @, an absolute path to a projection in WKT.
layers=14
bbox=218337.16112593404,889611.9317974453,248183.9359890727,914312.7109945256
tilecache-2.11/docs/PaxHeader/index.txt 000644 777777 777777 00000000210 11125407126 021747 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142718
24 SCHILY.dev=234881029
22 SCHILY.ino=3311450
18 SCHILY.nlink=1
tilecache-2.11/docs/index.txt 000644 473017214730172100000000666 11125407126 020153 0 ustar 00christos christos 000000 000000 .. TileCache documentation master file, created by sphinx-quickstart on Sat Dec 27 06:07:30 2008.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to TileCache's documentation!
=====================================
Contents:
.. toctree::
:maxdepth: 2
README
Caches
EXAMPLES
SuperOverlays
CONTRIBUTORS
NEWS
LICENSE
* :ref:`search`
tilecache-2.11/docs/PaxHeader/LICENSE.txt 000644 777777 777777 00000000210 11456032102 021715 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142718
24 SCHILY.dev=234881029
22 SCHILY.ino=3311447
18 SCHILY.nlink=1
tilecache-2.11/docs/LICENSE.txt 000644 473017214730172100000004145 11456032102 020115 0 ustar 00christos christos 000000 000000 License
-------
Copyright (c) 2006-2010 TileCache Contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of TileCache nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The TileCache/Caches/S3.py file is distributed by Amazon as part of their S3
example library. The license for that file is:
This software code is made available "AS IS" without warranties of any
kind. You may copy, display, modify and redistribute the software
code either by itself or as incorporated into your code; provided that
you do not remove any proprietary notices. Your use of this software
code is at your own risk and you waive any claim against Amazon
Digital Services, Inc. or its affiliates with respect to your use of
this software code. (c) 2006-2010 Amazon Digital Services, Inc. or its
affiliates.
tilecache-2.11/docs/PaxHeader/Makefile 000644 777777 777777 00000000210 11125407126 021537 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142718
20 atime=1287142718
24 SCHILY.dev=234881029
22 SCHILY.ino=3311458
18 SCHILY.nlink=1
tilecache-2.11/docs/Makefile 000644 473017214730172100000004477 11125407126 017747 0 ustar 00christos christos 000000 000000 # Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d _build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html web pickle htmlhelp latex changes linkcheck
help:
@echo "Please use \`make ' where is one of"
@echo " html to make standalone HTML files"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " changes to make an overview over all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
clean:
-rm -rf _build/*
html:
mkdir -p _build/html _build/doctrees
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) _build/html
@echo
@echo "Build finished. The HTML pages are in _build/html."
pickle:
mkdir -p _build/pickle _build/doctrees
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) _build/pickle
@echo
@echo "Build finished; now you can process the pickle files."
web: pickle
json:
mkdir -p _build/json _build/doctrees
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) _build/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
mkdir -p _build/htmlhelp _build/doctrees
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) _build/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in _build/htmlhelp."
latex:
mkdir -p _build/latex _build/doctrees
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) _build/latex
@echo
@echo "Build finished; the LaTeX files are in _build/latex."
@echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
"run these through (pdf)latex."
changes:
mkdir -p _build/changes _build/doctrees
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) _build/changes
@echo
@echo "The overview file is in _build/changes."
linkcheck:
mkdir -p _build/linkcheck _build/doctrees
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) _build/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in _build/linkcheck/output.txt."
tilecache-2.11/docs/PaxHeader/NEWS.txt 000644 777777 777777 00000000210 11456027571 021425 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142718
20 atime=1287142718
24 SCHILY.dev=234881029
22 SCHILY.ino=3311453
18 SCHILY.nlink=1
tilecache-2.11/docs/NEWS.txt 000644 473017214730172100000017442 11456027571 017631 0 ustar 00christos christos 000000 000000 Changelog
=========
tilecache-2.11, Fri 15 Oct 2010 06:36:11 -0500
* Change copyright statements to be more accurate
* Add minimal (read-only, non-optimized) support for the
MBTiles sqlite format
* Fix a bug introduced in disk locking prior to 2.0.3
* Add sendfile and Expires support to tilecache.
* Other minor improvements to documentation and pre-seeding.
tilecache-2.10, Sun, 18 Jan 2009 21:07:49 -0500
* APPLICATION CHANGE: tilecache_seed.py now uses optparse for options
parsing, which may require changes in scripts which call tilecache_seed
programatically. See the docs for the new style of command line.
* Add support to S3 cache for TMS-style URLs (thx stvn)
* Fixes for Caches/Disk.py under Jython
* Support multiple TileCacheConfigs in the same mod_python server (thx fredj)
* Add support for combining multiple tilecache layers into a single image when
using WMS. (thx fredj)
* allow custom mime_types in MapServer, WMS layers (thx fredj)
* improve KML links to not link to invalid tiles (thx Graham Carlyle)
* add png256 support to TileCache using Mapnik (thx Dane Springmeyer)
* A number of other patches from the mailing list.
tilecache-2.04, Mon, 23 Jun 2008 14:00:54 -0400
* Add support for JSON-output of layer information
* Add 'data_extent' property to allow for informing remote clients of
extent of data (seperate from grid extent)
* Minor fixes to layer initialization with regard to spherical mercator,
error logging, and others.
tilecache-2.03, Mon, 19 May 2008 23:13:09 -0400
* Adding metadata about layers, etc. for allowing external clients
to better understand the parameters used by a layer.
* Improve programatic access to KML SuperOverlay output
* Add SuperOverlay documentation designed to assist integrators.
* Fix a bug in Memcache support with Metatiles.
* Fix ordering of mod_python cache loading to load local paths first.
tilecache-2.02, Sat, 10 May 2008 09:21:47 -0400
* Add GoogleDisk cache, to save tiles to disk in z/x/y.ext format
* Add VETMS Service, provided by Steven Ottens
* Add "Test" cache, which doesn't cache anything, for debugging
* Fix Image Layer
* Add GDAL Layer, for reading images via GDAL directly
* Add support for reprojecting ArcXML layers
* Add threading support to standalone http server
* Support for Mapnik 0.5
* Support spitting out crossdomain.xml
* Username/password support for WMS Layers
* mod_python re-reads tilecache.cfg if it changed
* Protect disk cache from os.makedirs race condition
* Bump decimals in TMS,WMS-C units-per-pixel in caps output
* Minor Changes in KML SuperOverlays
tilecache-2.01, Thu, 27 Dec 2007 08:40:43 -0500
* Add Amazon S3 Cache support.
* Add cache documentation
* Improved error handling in server startup
* Many minor cleanups of documentation, etc.
tilecache-2.0, Sat, 22 Dec 2007 23:35:03 -0500
* Refactor TileCache to support drop in plugins for just about everything.
* Upated TileCache release with KML SuperOverlay support
* Add MGMaps service.
* Add ArcXML layer.
* Make code compatible with PyPI.
* Cleaning up and moving around a bunch of distribution related stuff.
tilecache-1.9, Wed, 5 Sep 2007 11:14:16 -0400
* Fix longstanding bug which made some non-geographic projections difficult
to create tiles with
* Add more informative error message output via TileCacheExceptions
* Fix for "MetaLayer.getMetaSize is too conservative"
* Report OSErrors more cleanly in tilecache_clean.py
* Better support for Jython in DiskCache class.
* Add support for extent_type=loose to allow out of bounds tile requests
* Improved tilecache_seed to only grab one metaTile from each set --
this drastically reduces the number of requests to precache metatiled
layers. Also fixed off-by-one error where seed was requesting too many
tiles.
* Add tms_type=google to specify that the TMS layer should go down instead
of up.
* Add setting of labelcache_map_edge_buffer to the MapServer layer if one
does not exist on the map object.
* Make mapnik layer respect layers= config if provided.
* Remove getClosestLevel, no longer used or neccesary.
* Better Lockfile removal, from Paul Spencer
* Update WMS Capabilities, from Steven Ottens
* Only use metaTiling if metatile=yes, true, or 1
* Minor change to WMS layer dispatching to handle GDAL WMS Driver
compatability.
tilecache-1.8, Fri, 4 May 2007 07:31:38 -0400
* Patch to ImageLayer from Volker Mische add:
* Optional transparency to images which are not transparent. This allows
the images to be transparent outside the maxExtent of the image.
* Resize scaling method specification
* Add support for tile watermarking, patch by Andrew Hughes.
* Allow for definition of 'styles' parameter in WMSLayer tilecache
cfg -- don't send blank parameters to the backend.
tilecache-1.7, Fri, 13 Apr 2007 20:34:42 -0400
* Apache will sometimes kill TileCache, leaving around locks. If we can't
lock for > cache.timeout seconds, throw an exception with the lockname,
so that users can cleanup. Reported by Brock Anderson, who had stuck locks
for several days.
* If ImageLayer base image is transparent, make output Image transparent too.
Report and patch by Brian Victor.
* Add support for forcing client to reload on errors, by Suki Hirata.
* Add support for not caching data which is not images for WMS, with
original support written by Suki Hirata.
* Minor fixups to TMS metadata, from Suki Hirata.
tilecache-1.6, Thu Apr 5 19:09:58 EDT 2007
* Added Python distutils and Debian packaging materials.
* Added CONTRIBUTORS and EXAMPLES documentation files.
tilecache-1.5, Tue Mar 27 10:17:57 EDT 2007
* Client.py support reading Layer config from tilecache.cfg, from Hani Howari
* Added ImageLayer.
* Support for readonly caches
* Add utility for cleaning a tilecache DiskCache to a certain size.
* Minor distribution/documentation changes.
tilecache-1.4, Sat Feb 3 21:56:02 EST 2007
* Added wsgi handler, from Ehud Shabtai.
* Added standalone HTTP server, using wsgi handler, from Ehud Shabtai.
* Added fastcgi implementation, using wsgi handler, from Ehud Shabtai.
* Improved documentation, including patch from Eric Lemoine.
* Support for 'maxResolution' layer option.
* Improved support for running as CGI under IIS, from Suki Hirata.
tilecache-1.3, Tue Dec 5 23:40:49 EST 2006
* Fix metaTile support:
* Data was offset downwards by metaBuffer pixels.
* metabuffer and metasize parsing was not working.
* Add support for palatted transparency when using metaTiling. Patch by
Matthew Perry
* Fix for Windows support: os.rename() won't overwrite files. Patch by Tim
Schaub
* Added 'description' metadata as a layer property.
* and support added to TMS metadata.
* Documented layer configuration parameters.
tilecache-1.2, Mon Dec 4 01:15:41 EST 2006
* Add support for WorldWind style requests, courtesy of Emily Gouge, from
Refractions.
* Add support for MapnikLayer for rendering.
* Add support for rendering using metatiles: instead of rendering one tile
at a time, render a 5x5 tileset, and then slice the tiles up. Good for
vector layers, where labels crossing tile boundaries is useful.
To turn on, use 'metaTile=yes' in layer definition. Requires
Python-Imaging.
* Improved TMS metadata
* Fix TileCache to work on Python 2.2
* Fix TileCache to work on Windows.
tilecache-1.1, Fri Nov 17 14:56:56 EST 2006
* Allow non-integer aspect ratios for bounding boxes
* Add support for bounding box passed on command line to Client.py
* Change cache to use local layer name for creating caches instead of
remote layer list. After installing 1.1, if you have DiskCaches
where the local layer name does not match the remote layer name,
you should move your directory after installing tilecache-1.1.
tilecache-1.0, Fri Nov 10 13:14:02 EST 2006
* Initial Release
tilecache-2.11/docs/PaxHeader/README.txt 000644 777777 777777 00000000210 11456032102 021570 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142718
20 atime=1287142718
24 SCHILY.dev=234881029
22 SCHILY.ino=3311455
18 SCHILY.nlink=1
tilecache-2.11/docs/README.txt 000644 473017214730172100000042374 11456032102 017776 0 ustar 00christos christos 000000 000000 =================
Getting Started
=================
-------------------------
Cache and serve map tiles
-------------------------
:Author: labs@metacarta.com
:Copyright: (c) 2006-2010 TileCache Contributors
Distributed under the BSD license.
:Version: 2.11
:Manual section: 8
:Manual group: GIS Utilities
Description
===========
TileCache is a BSD licensed tile caching mechanism. The goal is to make it
easy to set up a WMS or TMS frontend to any backend data services you might be
interested in, using a pluggable caching and rendering mechanism.
TileCache was developed by MetaCarta Labs and released to the public under a
BSD license.
The TileCache was designed as a companion to OpenLayers, the BSD licensed web
mapping interface. If you are using TileCache with OpenLayers, please read the
section of this readme which describes how to do so. For additional help with
setting up TileCache for use with OpenLayers, please feel free to stop by
#openlayers, on irc.freenode.net, or to send email to
tilecache@openlayers.org.
Installing TileCache
====================
Generally, installing TileCache is as simple as downloading a source
distribution and unpacking it. For installation systemwide, you can also use
the Python Package Index (aka pypi or Cheeseshop) to install TileCache. Simply
type easy_install TileCache. Once this is done, you will need to install the
TileCache configuration file. A tool to do this is installed, called
tilecache_install_config.py. A full installation likely looks like::
$ sudo easy_install TileCache
...
Installed
/usr/lib/python2.5/site-packages/TileCache-2.10-py2.5.egg
$ sudo tilecache_install_config.py
Successfully copied file
/usr/lib/python2.5/site-packages/TileCache-2.10-py2.5.egg/TileCache/tilecache.cfg
to /etc/tilecache.cfg.
TileCache is also available as a Debian package from the TileCache homepage.
This Debian package is designed to install on Debian etch releases or later.
This Debian package should install on Ubuntu Feisty or Gutsy.
Running Under CGI
=================
* Extract the code to some web directory (e.g. in /var/www).
* Edit tilecache.cfg to point the DiskCache to the location you wish
to cache tiles, and the layers to point to the map file or WMS
server you wish to cache. On Debian, this file is in /etc/tilecache.cfg
by default.
* Permit CGI execution in the TileCache directory.
For example, if TileCache is to be run with Apache, the
following must be added in your Apache configuration,
where /var/www/tilecache is the directory resulting from
the code extraction. On Debian, this is typically /usr/lib/cgi-bin.
::
AddHandler cgi-script .cgi
Options +ExecCGI
* Visit:
http://example.com/yourdir/tilecache.cgi?LAYERS=basic&SERVICE=WMS
&VERSION=1.1.1&REQUEST=GetMap&SRS=EPSG:4326&BBOX=-180,-90,0,90
&WIDTH=256&HEIGHT=256
* Or visit:
http://example.com/yourdir/tilecache.cgi/1.0.0/basic/0/0/0.png
* If you see a tile you have set up your configuration correctly. Congrats!
Non-standard Python Location
----------------------------
If your Python is not at /usr/bin/python on your system, you will need to
change the first line of tilecache.cgi to reference the location of your Python
binary. A common example is:
::
#!/usr/local/bin/python
Under Apache, you might see an error message like:
::
[Wed Mar 14 19:55:30 2007] [error] [client 127.0.0.1] (2)No such file or
directory: exec of '/www/tilecache.cgi' failed
to indicate this problem.
You can typically locate where Python is installed on your system via the
command which python.
Windows users: If you are using Windows, you should change the first line
of tilecache.cgi to read:
::
#!C:/Python/python.exe -u
C:/Python should match the location Python is installed under on your
system. In Python 2.5, this location is C:/Python25 by default.
Running Under mod_python
========================
* Extract the code to some web directory (e.g. /var/www).
* Edit tilecache.cfg to point the DiskCache to the location you wish
to cache tiles, and the layers to point to the map file or WMS
server you wish to cache
* Add the following to your Apache configuration, under a heading:
::
AddHandler python-program .py
PythonHandler TileCache.Service
PythonOption TileCacheConfig /path/to/tilecache.cfg
* An example might look like:
::
AddHandler python-program .py
PythonHandler TileCache.Service
PythonOption TileCacheConfig /var/www/tilecache/tilecache.cfg
* In this example, /var/www/tilecache is the directory resulting from
the code extraction. If you've installed this from a Debian package, the
location of your .cfg file is probably /etc/tilecache.cfg.
* Edit tilecache.cfg to point to the location of your 'Layers' directory,
as demonstrated inside the default tilecache.cfg.
* Visit one of the URLs described above, replacing tilecache.cgi with
tilecache.py
* If you see a tile you have set up your configuration correctly. Congrats!
Running Standalone under WSGI
=============================
TileCache as of version 1.4 comes with a standalone HTTP server which uses
the WSGI handler. This implementation depends on *Python Paste*, which can be
downloaded from:
http://cheeseshop.python.org/pypi/Paste
For versions of Python earlier than 2.5, you will also need to install
wsgiref:
http://cheeseshop.python.org/pypi/wsgiref
Once you have all the prerequisites installed, simply run:
::
python tilecache_http_server.py
This will start a webserver listening on port 8080, after which you should
be able to open:
::
http://hostname:8080/1.0.0/basic/0/0/0.png
to see your first tile.
Running Under FastCGI
=====================
TileCache as of version 1.4 comes with a fastcgi implementation. In
order to use this implementation, you will need to install flup, available
from:
http://trac.saddi.com/flup
This implementation also depends on Python Paste, which can be downloaded
from:
http://cheeseshop.python.org/pypi/Paste
Once you have done this, you can configure your fastcgi server to use
tilecache.fcgi.
Configuring FastCGI is beyond the scope of this documentation.
Running Under IIS
=================
Installing TileCache for use with IIS requires some additional configuration.
A nice document for setting up TileCache on IIS is available from Vish's
weblog: http://viswaug.wordpress.com/2008/02/03/setting-up-tilecache-on-iis/ .
Running Standalone with PasteScript and CherryPy
================================================
One component of the CherryPy web framework is a pure Python, fast,
HTTP/1.1-compliant, WSGI thread-pooled webserver.
To deploy Tilecache using this option you have to:
* Install prerequisites:
easy_install PasteScript
easy_install CherryPy
* Create a deployment config file specifying the http server and the
application with options. The format of the configuration file is
documented here: http://pythonpaste.org/deploy/#the-config-file
Example configuration file follows. Copy the lines into tc.ini, tweak
the tilecache_config variable, run paster serve tc.ini and enjoy at
http://127.0.0.1:5000/tc
::
[server:main]
#tested with Paste#http and PasteScript#wsgiutils, PasteScript#twisted
also possible after installing dependencies
use = egg:PasteScript#cherrypy
host = 127.0.0.1
port = 5000
[composite:main]
use = egg:Paste#urlmap
/tc = tilecache1
[app:tilecache1]
use = egg:TileCache
tilecache_config = tilecache.cfg
Configuration
=============
TileCache is configured by a config file, defaulting to tilecache.cfg.
There are several parameters to control TileCache layers that are applicable
to all layers:
bbox
The bounding box of the Layer. The resolutions array defaults
to having resolutions which are equal to the bbox divided by
512 (two standard tiles).
debug
Whether to send debug output to the error.log. Defaults to "yes",
can be set to "no"
description
Layer description, used in some metadata responses. Default
is blank.
extension
File extension of the layer. Used to request images from
WMS servers, as well as when writing cache files.
layers
A string used to describe the layers. Typically passed directly
to the renderer. The WMSLayer sends this in the HTTP request,
and the MapServerLayer chooses which layer to render based on
this string. If no layer is provided, the layer name is used
to fill this property.
levels
An integer, describing the number of 'zoom levels' or
scales to support. Overridden by resolutions, if passed.
mapfile
The absolute file location of a mapfile. Required for
MapServer and Mapnik layers.
maxResolution
The maximum resolution. If this is set, a resolutions
array is automatically calculated up to a number of
levels controlled by the 'levels' option.
metaTile
set to "yes" to turn on metaTiling. This will request larger
tiles, and split them up using the Python Imaging library.
Defaults to "no".
metaBuffer
an integer number of pixels to request around the outside
of the rendered tile. This is good to combat edge effects
in various map renderers. Defaults to 10.
metaSize
A comma seperated pair of integers, which is used to
determine how many tiles should be rendered when using
metaTiling. Default is 5,5.
resolutions
Comma seperate list of resolutions you want the TileCache
instance to support.
size
Comma seperated set of integers, describing the width/height
of the tiles. Defaults to 256,256
srs
String describing the SRS value. Default is "EPSG:4326"
type
The type of layer. Options are: WMSLayer, MapnikLayer, MapServerLayer,
ImageLayer
url
URL to use when requesting images from a remote WMS server. Required
for WMSLayer.
watermarkImage
The watermarkImage parameter is assigned on a per-layer basis.
This is a fully qualified path to an image you would like to apply to each
tile. We recommend you use a watermark image the same size as your tiles.
If using the default tile size, you should use a 256x256 image.
NOTE: Python Imaging Library DOES NOT support interlaced images.
watermarkOpacity
The watermarkOpacity parameter is assigned on a per-layer basis.
This configures the opacity of the watermark over the tile, it is a floating
point number between 0 and 1. Usage is optional and will otherwise default.
extent_type
Setting this to 'loose' will allow TileCache to generate tiles outside the
maximum bounding box. Useful for clients that don't know when to stop
asking for tiles.
tms_type
Setting this to "google" will cause tiles to switch vertical order (that
is, following the Google style x/y pattern).
Using TileCache With OpenLayers
===============================
To run OpenLayers with TileCache the URL passed to the OpenLayers.Layer.WMS
constructor must point to the TileCache script, i.e. tilecache.cgi or
tilecache.py. As an example see the index.html file included in the TileCache
distribution.
Note: index.html assumes TileCache is set up under CGI (see above). If you set
up TileCache under mod_python you'd need to slighly modify index.html: the URL
passed to the OpenLayers.Layer.WMS constructor must point to the mod_python
script as opposed to the CGI script, so replace tilecache.cgi with
tilecache.py. Similarly, you would need to edit this URL if you were to use
TileCache with the standalone HTTP Server or FastCGI.
The most important thing to do is to ensure that the OpenLayers Layer
has the same resolutions and bounding box as your TileCache layer. You can define
the resolutions in OpenLayers via the 'resolutions' option or the 'maxResolution'
option on the layer. The maxExtent should be defined to match the bbox parameter
of the TileCache layer.
If you are using TileCache for overlays, you should set the 'reproject' option
on the layer to 'false'.
Using TileCache With MapServer
==============================
MapServer has a map level metadata option, labelcache_map_edge_buffer, which
is set automatically by TileCache to the metaBuffer plus five when metaTiling
is on, if it is not set in the mapfile.
If you are using MetaTiling, be aware that MapServer generates interlaced
PNG files, which PIL will not read. See
http://www.mapserver.org/faq.html#why-doesn-t-pil-python-imaging-library-open-my-pngs on how to resolve this.
Using With Python-Mapscript
===========================
Several users have reported cases where large mapfiles combined with
python-mapscript has caused memory leaks, which eventually lead to
segfaults. If you are having problems with Apache/TileCache segfaults
when using python-mapscript, then you should switch to using a WMS
Layer instead of a MapServer Layer.
Seeding your TileCache
======================
The tilecache_seed.py utility will seed tiles in a cache automatically. You will
need to have TileCache set up in one of the previously described configurations.
Usage
-----
tilecache_seed.py [options] []
Options
-------
--version show program's version number and exit
-h, --help show this help message and exit
-f, --force force recreation of tiles even if they are already in
cache
-b BBOX, --bbox=BBOX restrict to specified bounding box
-p PADDING, --pading=PADDING
extra margin tiles to seed around target area.
Defaults to 0 (some edge tiles might be missing).
A value of 1 ensures all tiles will be created, but
some tiles may be wholly outside your bbox
Arguments
---------
layer
same layer name that is in the tilecache.cfg
zoom start
Zoom level to start the process
zoom end
Zoom level to end the process
Seeding by center point and radius
----------------------------------
If called without zoom level arguments, tilecache_seed.py will assume
that it needs to read a list of points and radii from standard input,
in the form:
::
,,,,,,,,
The format of this file is:
lon
the position(s) to seed longitude
lat
the position(s) to seed latitude
radius
the radius around the lon/lat to seed in degrees
Examples
--------
An example with zoom levels 5 through 12 and ~2 extra tiles around each zoom level would be like:
::
$ tilecache_seed.py Zip_Codes 5 12 "-118.12500,31.952162238,-116.015625,34.3071438563" 2
The bbox can be dropped and defaults to world lonlat(-180,-90,180,90):
::
$ tilecache_seed.py Zip_Codes 0 9
In center point/radius mode, the zoom level range is not specifiable from the
command-line. An example usage might look like:
::
$ tilecache_seed.py Zip_Codes
-118.12500,31.952162238,0.05
-121.46327,32.345345645,0.08
... the seeding will then commence ...
Cleaning your TileCache
=======================
The tilecache_clean.py utility will remove the least recently accessed
tiles from a cache, down to a specified size.
Usage
-----
tilecache_clean.py [options]
Options
-------
--version show program's version number and exit
-h, --help show this help message and exit
-s SIZE, --size=SIZE Maximum cache size, in megabytes.
-e ENTRIES, --entries=ENTRIES
Maximum cache entries. This limits the
amount of memory that will be used to store
information about tiles to remove.
Notes
-----
The --entries option to tilecache_clean.py is optional, and is used to regulate
how much memory it uses to do its bookkeeping. The default value of 1 million
will hopefully keep RAM utilization under about 100M on a 32-bit x86 Linux
machine. If tilecache_clean.py doesn't appear to be keeping your disk cache
down to an appropriate size, try upping this value.
tilecache_clean.py is designed to be run from a cronjob like so:
::
00 05 * * * /usr/local/bin/tilecache_clean.py -s500 /var/www/tilecache
Note that, on non-POSIX operating systems (particularly Windows),
tilecache_clean.py measures file sizes, and not disk usage. Because most
filesystems use entire file blocks for files smaller than a block, running du
-s or similar on your disk cache after a cleaning may still return a total
cache size larger than you expect.
TroubleShooting
===============
Occasionally, for some reason, when using meta tiles, your server may leave
behind lock files. If this happens, there will be files in your cache directory
with the extension '.lck'. If you are seeing tiles not render and taking
multiple minutes before returning a 500 error, you may be suffering under
a stuck lock.
Removing all files with extension '.lck' from the cache directory will
resolve this problem.
SEE ALSO
========
memcached(8)
http://tilecache.org/
http://openlayers.org/
http://wiki.osgeo.org/index.php/WMS_Tiling_Client_Recommendation
http://wiki.osgeo.org/index.php/Tile_Map_Service_Specification
tilecache-2.11/docs/PaxHeader/SuperOverlays.txt 000644 777777 777777 00000000210 11014437536 023470 x ustar 00christos christos 000000 000000 16 gid=10322897
16 uid=10322897
20 ctime=1287142717
20 atime=1287142718
24 SCHILY.dev=234881029
22 SCHILY.ino=3311448
18 SCHILY.nlink=1
tilecache-2.11/docs/SuperOverlays.txt 000644 473017214730172100000006732 11014437536 021674 0 ustar 00christos christos 000000 000000 Using KML SuperOverlays from TileCache
======================================
TileCache has support for KML superoverlays. For any TileCache layer for which
the source data is EPSG:4326, the KML Service provides GroundOverlay
data with LevelOfDetail NetworkLinks to deeper levels of data.
How to Use
----------
In order to display the KML data, there are two options:
* Create a link to a single tile which contains your tile of interest.
The tiling scheme for your data determines what the tile identifiers
are. Tiles match those used by TMS.
* Create a service that assembles multiple KML tile links into a single
KML document. This service should use NetworkLinks to point to other KML
files to include. This service does not need to be comple: it simply
needs to create small KML documents which include only a small number of
networklinks, needed to link the user to an area.
A simple document which does this -- for a given layername -- is included
in doc/examples/overlay.kml.
This sample document is designed to make available an entire worldwide set
of tiles via TileCache: typically, one would create a more complex KML
generator that would, for example, specify a LookAt tag as well, so that a user could open the data in Google Earth based on where they were looking.
Also, this KML file will let them zoom out -- but it means that the server
does need to generate (possibly many) KML documents to get the viewer to
where they want to be, because the KML Client will need to trawl its way
through the entire Pyramid down to where the user is viewing. However,
the image data is not included with the KML document, so this should be
a lightweight server side operation: it's just somewhat slow to do many
round trips, in general, so specifying (as a top level) some reasonaable
compromise between the whole world and the targeted viewing plane might make
sense.
Finding KML/Tile URLS
---------------------
TileCache KML documents are based around the TMS URL scheme. This means that
for a TMS tile:
http://tile.openaerialmap.org/tiles/1.0.0/openaerialmap/0/0/0.png
the corresponding KML document is
http://tile.openaerialmap.org/tiles/1.0.0/openaerialmap/0/0/0.kml
By default, TileCache uses a 'whole world' extent, split into two tiles:
western hemisphere and eastern. This means that to get the whole world into
Google Earth, you would need to include links to 0/0/0.kml and 0/0/1.kml.
TileCache can calculate a tile z/x/y from a bounding box using the getCell
function on a layer. To use this::
>>> import TileCache.Service
>>> s = TileCache.Service.load("tilecache.cfg")
>>> s.layers # doctest: +ELLIPSIS
{'basic': }
>>> s.layers['basic'] # doctest: +ELLIPSIS
>>> basic = s.layers['basic']
>>> basic.getCell((-180,-90,0,90))
(0, 0, 0)
>>> cell = basic.getCell((-10,-90,12,-80), exact=False)
>>> cell
(8, 0, 3)
Once you've done this, you can then use Python to construct a KML doc for the
tile::
>>> from TileCache.Layer import Tile
>>> tile = Tile(basic, cell[0], cell[1], cell[2])
>>> from TileCache.Services.KML import KML
>>> kml = KML(s)
>>> doc = kml.generate_kml_doc(tile, base_path="http://example.com/tilecache.cgi", include_wrapper=False)
>>> len(doc)
2546
>>> doc[550:600]
'\n \n \n