Virtual Earth compatible TC-cache

4 messages Options Options
Embed this Post
Permalink
Steven M. Ottens

Virtual Earth compatible TC-cache

Reply Threaded MoreMore options
Print post
Permalink
Hi all,

For those lost souls who want to create a cache which is directly
compatible with the virtual earth client I've attached a modified
disk.py, renamed to VE.py. It is written for TC 2.01 and should be put
in the <tilecache>/Cache folder.

Some information on the VE compatible cache structure:
http://msdn2.microsoft.com/en-us/library/bb259689.aspx

This VE cache is a flat file structure, which means that you need a
filesystem that can handle thousands of files in a directory. To be
honest the only reason why you would want to do this is so you can
directly add a dataset in virtualearth using the new
VETileSourceSpecification
 and have the files available in a web-accessible directory. The next
step will be to add a VE layer so you can use tilecache to dynamically
generate the VE-tiles.

The reason why you want to create VE-specific tiles is to be able to
view them in 3D (inside the VE viewer).

Regards,
Steven

# BSD Licensed, Copyright (c) 2006-2007 MetaCarta, Inc.

from TileCache.Cache import Cache
import sys, os, time

class VE (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):
        old_umask = os.umask(self.umask)
        os.makedirs(path)
        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,
                       "%s.%s" % (self.quad(tile),tile.layer.extension)
                    )
        filename = os.path.join( *components )
        return filename

    def quad (self, tile):
        quadKey = ''
        for i in range (tile.z, 0, -1):
              digit = 0
              mask = 1 << (i -1 )
              if (tile.x & mask) != 0:
                    digit=digit+1
              if (tile.y & mask) !=0:
                    digit=digit+2
              quadKey = quadKey + str(digit)
        return quadKey

    def get (self, tile):
        filename = self.getKey(tile)
        if self.access(filename, 'read'):
            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()
        old_umask = os.umask(self.umask)
        output = file(tmpfile, "wb")
        output.write(data)
        output.close()
        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)
            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()
                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 mailing list
Tilecache@...
http://openlayers.org/mailman/listinfo/tilecache
Steven M. Ottens

Re: Virtual Earth compatible TC-cache

Reply Threaded MoreMore options
Print post
Permalink
Hi all,

Once I finished it, I realised that it is actually quite a useless piece
of code. There is hardly any asiteuation where you want to store the
cache inside TC as VE-tiles without exposing them to the outer world. So
I decided to write a service instead. The will take a request with a
quadkey and calculate the row and column in epsg:900913:
A typical request would be
http://steef/tilecache.py?ve=true&layer=hoogtes&tile=120

where ve=true triggers the VETMS service in Service.py
layer=hoogtes gives yoou the layer
tile=120 gives you the quad key number.
120 in this case means z= 3, x=4 and y=5

In virtual earth you can add a tilecache-based layer this way:
 var tileSourceSpec = new VETileSourceSpecification("ahn",
"http://steef/tilecache.py?ve=true&layer=hoogtes&tile=%4");

Once again the only reason why you want to use this is if you're somehow
stuck with the VE-client, instead of a more friendly one like OpenLayers.

Attached the VETMS service also you need to add the following lines to
Service.py
       elif params.has_key("ve") and \
             params['ve'] == "true":
            from TileCache.Services.VETMS import VETMS
            tile = VETMS(self).parse(params, path_info, host)

just above:
       else:
            from TileCache.Services.TMS import TMS
            tile = TMS(self).parse(params, path_info, host)
(line 173)

Regards,
Steven
Steven M. Ottens wrote:

> Hi all,
>
> For those lost souls who want to create a cache which is directly
> compatible with the virtual earth client I've attached a modified
> disk.py, renamed to VE.py. It is written for TC 2.01 and should be put
> in the <tilecache>/Cache folder.
>
> Some information on the VE compatible cache structure:
> http://msdn2.microsoft.com/en-us/library/bb259689.aspx
>
> This VE cache is a flat file structure, which means that you need a
> filesystem that can handle thousands of files in a directory. To be
> honest the only reason why you would want to do this is so you can
> directly add a dataset in virtualearth using the new
> VETileSourceSpecification
> and have the files available in a web-accessible directory. The next
> step will be to add a VE layer so you can use tilecache to dynamically
> generate the VE-tiles.
>
> The reason why you want to create VE-specific tiles is to be able to
> view them in 3D (inside the VE viewer).
>
> Regards,
> Steven
> ------------------------------------------------------------------------
>
> _______________________________________________
> Tilecache mailing list
> Tilecache@...
> http://openlayers.org/mailman/listinfo/tilecache

# BSD Licensed, Copyright (c) 2006-2007 MetaCarta, Inc.

from TileCache.Service import Request, Capabilities
import TileCache.Layer as Layer


class VETMS (Request):
    def parse (self, fields, path, host):
        # <host>?ve=true&layer=global_mosaic&tile=000.jpg
        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, int(cell[0]), int(cell[1]), int(cell[2]))
        return tile

    def unQuad (self, quad):
        z = len(quad)
        col = int(0)
        row = int(pow(2,z)-1)
        quadint = int(0)
        cell = [0,0,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[0] = col
        cell[1] = row
        cell[2] = z
        return cell

    def serverCapabilities (self, host):
        return Capabilities("text/xml", """<?xml version="1.0" encoding="UTF-8" ?>
            <Services>
                <VETileMapService version="1.0.0" href="%s?ve=true/" />
            </Services>""" % host)


_______________________________________________
Tilecache mailing list
Tilecache@...
http://openlayers.org/mailman/listinfo/tilecache
Christopher Schmidt-2

Re: Virtual Earth compatible TC-cache

Reply Threaded MoreMore options
Print post
Permalink
On Tue, Feb 12, 2008 at 03:48:19PM +0100, Steven M. Ottens wrote:

> Hi all,
>
> Once I finished it, I realised that it is actually quite a useless piece
> of code. There is hardly any asiteuation where you want to store the
> cache inside TC as VE-tiles without exposing them to the outer world. So
> I decided to write a service instead. The will take a request with a
> quadkey and calculate the row and column in epsg:900913:
> A typical request would be
> http://steef/tilecache.py?ve=true&layer=hoogtes&tile=120
>
> where ve=true triggers the VETMS service in Service.py
> layer=hoogtes gives yoou the layer
> tile=120 gives you the quad key number.
> 120 in this case means z= 3, x=4 and y=5
>
> In virtual earth you can add a tilecache-based layer this way:
> var tileSourceSpec = new VETileSourceSpecification("ahn",
> "http://steef/tilecache.py?ve=true&layer=hoogtes&tile=%4");
>
> Once again the only reason why you want to use this is if you're somehow
> stuck with the VE-client, instead of a more friendly one like OpenLayers.
>
> Attached the VETMS service also you need to add the following lines to
> Service.py
>       elif params.has_key("ve") and \
>             params['ve'] == "true":
>            from TileCache.Services.VETMS import VETMS
>            tile = VETMS(self).parse(params, path_info, host)
>
> just above:
>       else:
>            from TileCache.Services.TMS import TMS
>            tile = TMS(self).parse(params, path_info, host)
> (line 173)

Can you turn this into a patch? checkout a copy of svn, add your file
via svn add, make the above change, and then 'svn diff' and send it ot
the list? I'll try and get it in if you do.

Regards,
--
Christopher Schmidt
MetaCarta
_______________________________________________
Tilecache mailing list
Tilecache@...
http://openlayers.org/mailman/listinfo/tilecache
Steven M. Ottens

Re: Virtual Earth compatible TC-cache

Reply Threaded MoreMore options
Print post
Permalink
I only send this to chris, so here it is for the list:

Attached

Christopher Schmidt wrote:

> On Tue, Feb 12, 2008 at 03:48:19PM +0100, Steven M. Ottens wrote:
>  
>> Hi all,
>>
>> Once I finished it, I realised that it is actually quite a useless piece
>> of code. There is hardly any asiteuation where you want to store the
>> cache inside TC as VE-tiles without exposing them to the outer world. So
>> I decided to write a service instead. The will take a request with a
>> quadkey and calculate the row and column in epsg:900913:
>> A typical request would be
>> http://steef/tilecache.py?ve=true&layer=hoogtes&tile=120
>>
>> where ve=true triggers the VETMS service in Service.py
>> layer=hoogtes gives yoou the layer
>> tile=120 gives you the quad key number.
>> 120 in this case means z= 3, x=4 and y=5
>>
>> In virtual earth you can add a tilecache-based layer this way:
>> var tileSourceSpec = new VETileSourceSpecification("ahn",
>> "http://steef/tilecache.py?ve=true&layer=hoogtes&tile=%4");
>>
>> Once again the only reason why you want to use this is if you're somehow
>> stuck with the VE-client, instead of a more friendly one like OpenLayers.
>>
>> Attached the VETMS service also you need to add the following lines to
>> Service.py
>>       elif params.has_key("ve") and \
>>             params['ve'] == "true":
>>            from TileCache.Services.VETMS import VETMS
>>            tile = VETMS(self).parse(params, path_info, host)
>>
>> just above:
>>       else:
>>            from TileCache.Services.TMS import TMS
>>            tile = TMS(self).parse(params, path_info, host)
>> (line 173)
>>    
>
> Can you turn this into a patch? checkout a copy of svn, add your file
> via svn add, make the above change, and then 'svn diff' and send it ot
> the list? I'll try and get it in if you do.
>
> Regards,
>  



Index: C:/Documents and Settings/steveno/workspace/tilecache/TileCache/Services/VETMS.py
===================================================================
--- C:/Documents and Settings/steveno/workspace/tilecache/TileCache/Services/VETMS.py (revision 0)
+++ C:/Documents and Settings/steveno/workspace/tilecache/TileCache/Services/VETMS.py (revision 0)
@@ -0,0 +1,49 @@
+# BSD Licensed, Copyright (c) 2006-2007 MetaCarta, Inc.
+
+from TileCache.Service import Request, Capabilities
+import TileCache.Layer as Layer
+
+
+class VETMS (Request):
+    def parse (self, fields, path, host):
+        # <host>?ve=true&layer=global_mosaic&tile=000.jpg
+        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, int(cell[0]), int(cell[1]), int(cell[2]))
+        return tile
+
+    def unQuad (self, quad):
+        z = len(quad)
+        col = int(0)
+        row = int(pow(2,z)-1)
+        quadint = int(0)
+        cell = [0,0,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[0] = col
+        cell[1] = row
+        cell[2] = z
+        return cell
+
+    def serverCapabilities (self, host):
+        return Capabilities("text/xml", """<?xml version="1.0" encoding="UTF-8" ?>
+            <Services>
+                <VETileMapService version="1.0.0" href="%s?ve=true/" />
+            </Services>""" % host)
+
Index: C:/Documents and Settings/steveno/workspace/tilecache/TileCache/Service.py
===================================================================
--- C:/Documents and Settings/steveno/workspace/tilecache/TileCache/Service.py (revision 253)
+++ C:/Documents and Settings/steveno/workspace/tilecache/TileCache/Service.py (working copy)
@@ -187,6 +187,10 @@
              (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("ve") and \
+             params['ve'] == "true":
+            from TileCache.Services.VETMS import VETMS
+            tile = VETMS(self).parse(params, path_info, host)
         else:
             from TileCache.Services.TMS import TMS
             tile = TMS(self).parse(params, path_info, host)



_______________________________________________
Tilecache mailing list
Tilecache@...
http://openlayers.org/mailman/listinfo/tilecache