
    (e                    V	   d dl mZ d dlZd dlZd dlZd dlZd dlZd dlZd dlZd dl	Z	d dl
Z
d dlZd dlZd dlZd dlmZ d dlmZmZmZmZmZ d dlmZ d dlmZ d dlmZmZ eZ	 d dlZd dlm Z  d dl!m"Z# d	Z$dZ&dZ'dZ( ejR                  d      Z*d Z+d Z, G d d      Z-ej\                  d        Z/ G d de0      Z1 G d de2      Z3i Z4g dZ5 ejl                  dd      Z7e7rejp                  js                  e7      Z9 ej                  ejp                  ju                  e9d            D ]  Z; e<e;d      j{                         Z>	  ej~                  e>j                  d            ZAeAe*j                  de;z          S	 e3j                  eA      ZDeDe4eDj                  <   e5j                  eDj                           ej                         ZHdZId ZJ G d! d"e2      ZK G d# d$e2      ZL G d% d&e2      ZM G d' d(e0      ZNdid)eOd*eOd+efd,ZPd-eQd+dfd.ZR	 djd/ZSdid0ZTd1ej                  d2ed+eeV   fd3ZWd1ej                  d2ed+eeej                     eeO   f   fd4ZYd5eej                     d2ed+eej                     fd6ZZd7ej                  d+e[fd8Z\	 djd9ej                  d:eej                     d;eej                     d2ee   d+ej                  f
d<Z]d= Z^	 djd>ej                  d?eeV   d2ee   d+ej                  fd@Z_dAeOd+eOfdBZ`	 djd>ej                  d2ee   d+ej                  fdCZad7ej                  d+eQfdDZbdE ZcdkdIZddJeQdKeeeQeQf      dLeOdFdGd2ef
dMZedJeQdLeOdFdGd+eeeeQeQf         fdNZfdFdGd+eQfdOZgd+ej                  fdPZidldQeeO   d+eeOeOef   fdRZjd2edSeOdLeOd+efdTZk G dU dHe2      Zl G dV dGe2      Zm G dW dXe0      Zn G dY dZe2      ZodSeOdLeOd2ed+eemeel   f   fd[Zp G d\ d]e2      Zqd^ ZrdSeOdLeOd2ed+dfd_ZsdSeOdLeOd2ed+dfd`Zt G da dbe2      Zu G dc dde2      Zvej                  d
fdQeeO   d+eQfdeZxdmdQeeO   d+eQfdfZyezdgk(  r% ej                   exej                  d	h             yy# e%$ r d
Z$Y w xY w# e0$ r dZAY w xY w# e1$ r Y fe0$ r e*j                  de;z          Y w xY w)n    )divisionN)partial)AnyListNoReturnOptionalTuple)uuid4)ElementTree)gdalosr)ImageTFz$Id$)averagenearbilinearcubiccubicsplinelanczos	antialiasmodemaxminmedq1q3)allgoogle
openlayersleafletmapmlnone
gdal2tilesc                     | j                  d      r(t        j                  | d      dk7  rt        d|        yt	        j
                  | d       y)z;Wrapper for os.makedirs() that can work with /vsi files too/vsii  r   zCannot create T)exist_okN)
startswithr   MkdirRecursive	Exceptionosmakedirs)paths    8/usr/lib/python3/dist-packages/osgeo_utils/gdal2tiles.pyr*   r*   _   sJ    vtU+q0nTF344 1 	D4(    c                     | j                  d      r;t        j                  |       }t        yt        j                  |j
                        S t        j                  j                  |       S )z>Wrapper for os.path.isfile() that can work with /vsi files toor$   F)	r&   r   VSIStatLstatS_ISREGr   r)   r+   isfile)r+   stat_ress     r,   r2   r2   h   sJ    v==&<||HMM**ww~~d##r-   c                       e Zd ZdZd Zd Zy)VSIFilez1Expose a simplistic file-like API for a /vsi filec                      || _         || _        y N)filenamef)selfr8   r9   s      r,   __init__zVSIFile.__init__v   s     r-   c                     t        j                  |dt        |      | j                        t        |      k7  rt	        d| j
                  z        y )N   zError while writing into %s)r   
VSIFWriteLlenr9   r(   r8   )r:   contents     r,   writezVSIFile.writez   s@    ??7As7|TVV<GL9DMMIJJ Mr-   N)__name__
__module____qualname____doc__r;   rA    r-   r,   r5   r5   s   s    ;Kr-   r5   c              #   ^  K   | j                  d      r_t        j                  | |      }|t        d|  d|       	 t	        | |       t        j
                  |      dk7  rt        d|        yt        | |       y# t        j
                  |      dk7  rt        d|        w xY ww)zDWrapper for open() built-in method that can work with /vsi files toor$   NzCannot open z in r   zCannot close )r&   r   	VSIFOpenLr(   r5   
VSIFCloseLopen)r8   r   r9   s      r,   my_openrK      s      6"NN8T*9l8*D?@@	<(A&&q!Q&-z :;; ' 8T"" q!Q&-z :;; 's   ;B-B 6B-(B**B-c                       e Zd Zy)UnsupportedTileMatrixSetNrB   rC   rD   rF   r-   r,   rM   rM          r-   rM   c                   F    e Zd Zd
dZd Zd Zd Zd Zede	dd fd	       Z
y)TileMatrixSetreturnNc                     d | _         d | _        d | _        d | _        d | _        d | _        d | _        d | _        d | _        y r7   )	
identifiersrs	topleft_x	topleft_ymatrix_widthmatrix_height	tile_size
resolutionlevel_countr:   s    r,   r;   zTileMatrixSet.__init__   sD     !r-   c                    | j                   | j                  z  |z  d|z  z  }t        || j                  z
  ||z  z        }t        || j                  | j
                  | j                  z  | j                   z  z
  z
  ||z  z        }||fS N   )r[   rZ   intrV   rW   rY   )r:   xyzoverriden_tile_sizerestxtys           r,   GeorefCoordToTileCoordz$TileMatrixSet.GeorefCoordToTileCoord   s    oo.1DD1M!dnn$/B)BCDNN((4>>9DOOKL ((*	
 2vr-   c                     t        | j                        D ]:  }| j                  | j                  z  |z  d|z  z  }||kD  s+t	        d|dz
        c S  | j                  dz
  S )?Maximal scaledown zoom of the pyramid closest to the pixelSize.r`   r   r=   )ranger\   r[   rZ   r   )r:   	pixelSizere   irf   s        r,   ZoomForPixelSizezTileMatrixSet.ZoomForPixelSize   si     t''( 	%A//DNN25HHAqDQC31a!e}$	% !##r-   c                     | j                   | j                  z  |z  d|z  z  }||z  | j                  z   }||z  | j                  | j                  | j                  z  | j                   z  z
  z   }||fS )FConverts pixel coordinates in given zoom level of pyramid to EPSG:3857r`   )r[   rZ   rV   rW   rY   )r:   pxpyzoomre   rf   mxmys           r,   PixelsToMeterszTileMatrixSet.PixelsToMeters   st     oo.1DD4P#X&#XNNT//$..@4??RR
 2vr-   c                     | j                  ||z  ||z  ||      \  }}| j                  |dz   |z  |dz   |z  ||      \  }}||||fS )z6Returns bounds of the given tile in georef coordinatesr=   )rw   )	r:   rg   rh   rt   re   minxminymaxxmaxys	            r,   
TileBoundszTileMatrixSet.TileBounds   sw     (($$$$	

d ((!V**!V**	

d dD$''r-   jc                    d| v sJ d| v sJ d| v sJ t        | d   t              sJ t        j                         }|j	                  t        | d               dk(  sJ |j                         xs |j                         }d}|j                         r|j                         }n4|j                         r$|j                         t        j                  z  dz  }t               }||_        t        | d         |_        t#        | d         D ]1  \  }}d|v sJ t        |d   t              sJ |d   }t%        |      dk(  sJ d	|v sJ d
|v sJ d|v sJ |d   }|d   }	|d
   }
|d   }|
|k7  rt'        d      |d	   dz  |z  }|r|	|}	}|dk(  r=||_        |	|_        ||_        |
|_        d|v sJ d|v sJ |d   |_        |d   |_        ||j(                  k7  s|	|j*                  k7  rt'        d      t5        |j,                  d|z  z  |z
        d|z  kD  rt'        d      |
|j.                  k7  s)t'        d       t%        | d         |_        |S )NrT   supportedCRS
tileMatrixr         ?   topLeftCornerr`   scaleDenominator	tileWidth
tileHeightr=   zOnly square tiles supportedgמY2?matrixWidthmatrixHeightz"All levels should have same origing:0yE>z2Only resolutions varying as power-of-two supportedz%All levels should have same tile size)
isinstancelistr   SpatialReferenceSetFromUserInputstrEPSGTreatsAsLatLongEPSGTreatsAsNorthingEastingIsProjectedGetLinearUnitsIsGeographicGetSemiMajormathpirQ   rU   rT   	enumerater?   rM   rV   rW   r[   rZ   rX   rY   absr\   )r~   rU   swapaxismetersPerUnittmsrn   r   r   rV   rW   r   r   r[   s                r,   parsezTileMatrixSet.parse   s   q   """q   !L/4000""$##C.(9$:;q@@@**,Q0O0O0Q??..0M,,.83>MoQ|_-&q7 '	MAz"j000j94@@@&7M}%***%333*,,,:---%a(I%a(I";/I#L1JJ&./LMM#$67'AMQJ'0)9	Av ) )!+ )$
222%333#-m#< $.~$>!-cmm1K23WXXs~~a0:=>
ARR2L  -2? K'	P ao.
r-   rR   N)rB   rC   rD   r;   ri   ro   rw   r}   staticmethoddictr   rF   r-   r,   rQ   rQ      s=    	  $(" 9 9/ 9 9r-   rQ   )mercatorgeodeticrasterr   ztms_MapML_APSTILE.jsonz
tms_*.jsonrbutf-8zCannot parse au  
globalmaptiles.py

Global Map Tiles as defined in Tile Map Service (TMS) Profiles
==============================================================

Functions necessary for generation of global tiles used on the web.
It contains classes implementing coordinate conversions for:

  - GlobalMercator (based on EPSG:3857)
       for Google Maps, Yahoo Maps, Bing Maps compatible tiles
  - GlobalGeodetic (based on EPSG:4326)
       for OpenLayers Base Map and Google Earth compatible tiles

More info at:

http://wiki.osgeo.org/wiki/Tile_Map_Service_Specification
http://wiki.osgeo.org/wiki/WMS_Tiling_Client_Recommendation
http://msdn.microsoft.com/en-us/library/bb259689.aspx
http://code.google.com/apis/maps/documentation/overlays.html#Google_Maps_Coordinates

Created by Klokan Petr Pridal on 2008-07-03.
Google Summer of Code 2008, project GDAL2Tiles for OSGEO.

In case you use this class in your product, translate it to another language
or find it useful for your project please let me know.
My email: klokan at klokan dot cz.
I would like to know where it was used.

Class is available under the open-source GDAL license (www.gdal.org).
    c                   p    e Zd ZdZddeddfdZd Zd Zd Zd	 Z	d
 Z
d Zd Zd Zd Zd Zd Zd Zd Zy)GlobalMercatoram  
    TMS Global Mercator Profile
    ---------------------------

    Functions necessary for generation of tiles in Spherical Mercator projection,
    EPSG:3857.

    Such tiles are compatible with Google Maps, Bing Maps, Yahoo Maps,
    UK Ordnance Survey OpenSpace API, ...
    and you can overlay them on top of base maps of those web mapping applications.

    Pixel and tile coordinates are in TMS notation (origin [0,0] in bottom-left).

    What coordinate conversions do we need for TMS Global Mercator tiles::

         LatLon      <->       Meters      <->     Pixels    <->       Tile

     WGS84 coordinates   Spherical Mercator  Pixels in pyramid  Tiles in pyramid
         lat/lon            XY in meters     XY pixels Z zoom      XYZ from TMS
        EPSG:4326           EPSG:387
         .----.              ---------               --                TMS
        /      \     <->     |       |     <->     /----/    <->      Google
        \      /             |       |           /--------/          QuadTree
         -----               ---------         /------------/
       KML, public         WebMapService         Web Clients      TileMapService

    What is the coordinate extent of Earth in EPSG:3857?

      [-20037508.342789244, -20037508.342789244, 20037508.342789244, 20037508.342789244]
      Constant 20037508.342789244 comes from the circumference of the Earth in meters,
      which is 40 thousand kilometers, the coordinate origin is in the middle of extent.
      In fact you can calculate the constant as: 2 * math.pi * 6378137 / 2.0
      $ echo 180 85 | gdaltransform -s_srs EPSG:4326 -t_srs EPSG:3857
      Polar areas with abs(latitude) bigger then 85.05112878 are clipped off.

    What are zoom level constants (pixels/meter) for pyramid with EPSG:3857?

      whole region is on top of pyramid (zoom=0) covered by 256x256 pixels tile,
      every lower zoom level resolution is always divided by two
      initialResolution = 20037508.342789244 * 2 / 256 = 156543.03392804062

    What is the difference between TMS and Google Maps/QuadTree tile name convention?

      The tile raster itself is the same (equal extent, projection, pixel size),
      there is just different identification of the same raster tile.
      Tiles in TMS are counted from [0,0] in the bottom-left corner, id is XYZ.
      Google placed the origin [0,0] to the top-left corner, reference is XYZ.
      Microsoft is referencing tiles by a QuadTree name, defined on the website:
      http://msdn2.microsoft.com/en-us/library/bb259689.aspx

    The lat/lon coordinates are using WGS84 datum, yes?

      Yes, all lat/lon we are mentioning should use WGS84 Geodetic Datum.
      Well, the web clients like Google Maps are projecting those coordinates by
      Spherical Mercator, so in fact lat/lon coordinates on sphere are treated as if
      the were on the WGS84 ellipsoid.

      From MSDN documentation:
      To simplify the calculations, we use the spherical form of projection, not
      the ellipsoidal form. Since the projection is used only for map display,
      and not for displaying numeric coordinates, we don't need the extra precision
      of an ellipsoidal projection. The spherical projection causes approximately
      0.33 percent scale distortion in the Y direction, which is not visually
      noticeable.

    How do I create a raster in EPSG:3857 and convert coordinates with PROJ.4?

      You can use standard GIS tools like gdalwarp, cs2cs or gdaltransform.
      All of the tools supports -t_srs 'epsg:3857'.

      For other GIS programs check the exact definition of the projection:
      More info at http://spatialreference.org/ref/user/google-projection/
      The same projection is designated as EPSG:3857. WKT definition is in the
      official EPSG database.

      Proj4 Text:
        +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0
        +k=1.0 +units=m +nadgrids=@null +no_defs

      Human readable WKT format of EPSG:3857:
         PROJCS["Google Maps Global Mercator",
             GEOGCS["WGS 84",
                 DATUM["WGS_1984",
                     SPHEROID["WGS 84",6378137,298.257223563,
                         AUTHORITY["EPSG","7030"]],
                     AUTHORITY["EPSG","6326"]],
                 PRIMEM["Greenwich",0],
                 UNIT["degree",0.0174532925199433],
                 AUTHORITY["EPSG","4326"]],
             PROJECTION["Mercator_1SP"],
             PARAMETER["central_meridian",0],
             PARAMETER["scale_factor",1],
             PARAMETER["false_easting",0],
             PARAMETER["false_northing",0],
             UNIT["metre",1,
                 AUTHORITY["EPSG","9001"]]]
    rZ   rR   Nc                     || _         dt        j                  z  dz  | j                   z  | _        dt        j                  z  dz  dz  | _        y)z*Initialize the TMS Global Mercator pyramidr`   iRa        @N)rZ   r   r   initialResolutionoriginShift)r:   rZ   s     r,   r;   zGlobalMercator.__init__  sA    "!"TWWw!6!Gtww;036r-   c                     || j                   z  dz  }t        j                  t        j                  d|z   t        j                  z  dz              t        j                  dz  z  }|| j                   z  dz  }||fS )zKConverts given lat/lon in WGS84 Datum to XY in Spherical Mercator EPSG:3857     f@Z        v@)r   r   logtanr   )r:   latlonru   rv   s        r,   LatLonToMeterszGlobalMercator.LatLonToMeters  sm     4###e+XXdhhSDGG3e;<=5Q$"""U*2vr-   c                     || j                   z  dz  }|| j                   z  dz  }dt        j                  z  dt        j                  t        j                  |t        j                  z  dz              z  t        j                  dz  z
  z  }||fS )zMConverts XY point from Spherical Mercator EPSG:3857 to lat/lon in WGS84 Datumr   r   r`   r   )r   r   r   atanexp)r:   ru   rv   r   r   s        r,   MetersToLatLonzGlobalMercator.MetersToLatLon  s     D$$$-D$$$- gg499TXXcDGGme&;<==#MO 	
 Cxr-   c                 t    | j                  |      }||z  | j                  z
  }||z  | j                  z
  }||fS )rq   
Resolutionr   )r:   rr   rs   rt   rf   ru   rv   s          r,   rw   zGlobalMercator.PixelsToMeters  sC     ood##X(((#X(((2vr-   c                 t    | j                  |      }|| j                  z   |z  }|| j                  z   |z  }||fS )zCConverts EPSG:3857 to pyramid pixel coordinates in given zoom levelr   )r:   ru   rv   rt   rf   rr   rs   s          r,   MetersToPixelszGlobalMercator.MetersToPixels  sE     ood#4###s*4###s*2vr-   c                     t        t        j                  |t        | j                        z        dz
        }t        t        j                  |t        | j                        z        dz
        }||fS )z9Returns a tile covering region in given pixel coordinatesr=   ra   r   ceilfloatrZ   r:   rr   rs   rg   rh   s        r,   PixelsToTilezGlobalMercator.PixelsToTile  Y     2dnn 556:;2dnn 556:;2vr-   c                 .    | j                   |z  }|||z
  fS )z7Move the origin of pixel coordinates to top-left cornerrZ   )r:   rr   rs   rt   mapSizes        r,   PixelsToRasterzGlobalMercator.PixelsToRaster  s!     ..D(7R<r-   c                 R    | j                  |||      \  }}| j                  ||      S )z+Returns tile for given mercator coordinates)r   r   )r:   ru   rv   rt   rr   rs   s         r,   MetersToTilezGlobalMercator.MetersToTile  s/     $$RT2B  R((r-   c                     | j                  || j                  z  || j                  z  |      \  }}| j                  |dz   | j                  z  |dz   | j                  z  |      \  }}||||fS )z9Returns bounds of the given tile in EPSG:3857 coordinatesr=   )rw   rZ   )r:   rg   rh   rt   ry   rz   r{   r|   s           r,   r}   zGlobalMercator.TileBounds  su     ((dnn)<b4>>>QSWX
d((!Vt~~%Q$..'@$

d dD$''r-   c                     | j                  |||      }| j                  |d   |d         \  }}| j                  |d   |d         \  }}||||fS )zHReturns bounds of the given tile in latitude/longitude using WGS84 datumr   r=   r`      )r}   r   )	r:   rg   rh   rt   boundsminLatminLonmaxLatmaxLons	            r,   TileLatLonBoundszGlobalMercator.TileLatLonBounds  sa     R.,,VAYq	B,,VAYq	B//r-   c                 &    | j                   d|z  z  S )zDResolution (meters/pixel) for given zoom level (measured at Equator)r`   )r   r:   rt   s     r,   r   zGlobalMercator.Resolution
  s     %%D11r-   c                     t        t              D ]'  }|| j                  |      kD  st        d|dz
        c S  t        dz
  S rk   r   r=   rl   MAXZOOMLEVELr   r   r:   rm   rn   s      r,   ro   zGlobalMercator.ZoomForPixelSize  F     |$ 	%A4??1--1a!e}$	% ar-   c                     |d|z  dz
  |z
  fS )z8Converts TMS tile coordinates to Google Tile coordinatesr`   r=   rF   )r:   rg   rh   rt   s       r,   
GoogleTilezGlobalMercator.GoogleTile  s     AtGaK2%%%r-   c                     d}d|z  dz
  |z
  }t        |dd      D ]4  }d}d|dz
  z  }||z  dk7  r|dz  }||z  dk7  r|dz  }|t        |      z  }6 |S )z3Converts TMS tile coordinates to Microsoft QuadTree r`   r=   r   )rl   r   )r:   rg   rh   rt   quadKeyrn   digitmasks           r,   QuadTreezGlobalMercator.QuadTree  s     gkRtQ# 	"AEQ<DT	a
T	a
s5z!G	" r-      )rB   rC   rD   rE   ra   r;   r   r   rw   r   r   r   r   r}   r   r   ro   r   r   rF   r-   r,   r   r   T  s]    `D7# 7 7 )(02 &r-   r   c                   V    e Zd ZdZddee   deddfdZd Zd Z	d	 Z
d
 Zd Zd Zd Zy)GlobalGeodetica  
    TMS Global Geodetic Profile
    ---------------------------

    Functions necessary for generation of global tiles in Plate Carre projection,
    EPSG:4326, "unprojected profile".

    Such tiles are compatible with Google Earth (as any other EPSG:4326 rasters)
    and you can overlay the tiles on top of OpenLayers base map.

    Pixel and tile coordinates are in TMS notation (origin [0,0] in bottom-left).

    What coordinate conversions do we need for TMS Global Geodetic tiles?

      Global Geodetic tiles are using geodetic coordinates (latitude,longitude)
      directly as planar coordinates XY (it is also called Unprojected or Plate
      Carre). We need only scaling to pixel pyramid and cutting to tiles.
      Pyramid has on top level two tiles, so it is not square but rectangle.
      Area [-180,-90,180,90] is scaled to 512x256 pixels.
      TMS has coordinate origin (for pixels and tiles) in bottom-left corner.
      Rasters are in EPSG:4326 and therefore are compatible with Google Earth.

         LatLon      <->      Pixels      <->     Tiles

     WGS84 coordinates   Pixels in pyramid  Tiles in pyramid
         lat/lon         XY pixels Z zoom      XYZ from TMS
        EPSG:4326
         .----.                ----
        /      \     <->    /--------/    <->      TMS
        \      /         /--------------/
         -----        /--------------------/
       WMS, KML    Web Clients, Google Earth  TileMapService
    tmscompatiblerZ   rR   Nc                 h    || _         |rd| j                   z  | _        y d| j                   z  | _        y )Nr   r   )rZ   resFact)r:   r   rZ   s      r,   r;   zGlobalGeodetic.__init__R  s0    " !4>>1DL !4>>1DLr-   c                 N    | j                   d|z  z  }d|z   |z  }d|z   |z  }||fS )zLConverts lon/lat to pixel coordinates in given zoom of the EPSG:4326 pyramidr`   r   r   r   )r:   r   r   rt   rf   rr   rs   s          r,   LonLatToPixelszGlobalGeodetic.LonLatToPixels^  s;     llQW$Ci33h#2vr-   c                     t        t        j                  |t        | j                        z        dz
        }t        t        j                  |t        | j                        z        dz
        }||fS )zDReturns coordinates of the tile covering region in pixel coordinatesr=   r   r   s        r,   r   zGlobalGeodetic.PixelsToTilef  r   r-   c                 R    | j                  |||      \  }}| j                  ||      S )z@Returns the tile for zoom which covers given lon/lat coordinates)r   r   )r:   r   r   rt   rr   rs   s         r,   LonLatToTilezGlobalGeodetic.LonLatToTilem  s/     $$S#t4B  R((r-   c                 &    | j                   d|z  z  S )zAResolution (arc/pixel) for given zoom level (measured at Equator)r`   r   r   s     r,   r   zGlobalGeodetic.Resolutions  s     ||ag%%r-   c                     t        t              D ]'  }|| j                  |      kD  st        d|dz
        c S  t        dz
  S r   r   r   s      r,   ro   zGlobalGeodetic.ZoomForPixelSizex  r   r-   c                     | j                   d|z  z  }|| j                  z  |z  dz
  || j                  z  |z  dz
  |dz   | j                  z  |z  dz
  |dz   | j                  z  |z  dz
  fS )z Returns bounds of the given tiler`   r   r   r=   )r   rZ   )r:   rg   rh   rt   rf   s        r,   r}   zGlobalGeodetic.TileBounds  s~    llQW$#%+#%*!Vt~~%+c1!Vt~~%+b0	
 	
r-   c                 L    | j                  |||      }|d   |d   |d   |d   fS )z1Returns bounds of the given tile in the SWNE formr=   r   r   r`   )r}   )r:   rg   rh   rt   bs        r,   r   zGlobalGeodetic.TileLatLonBounds  s3    OOBD)!adAaD!A$''r-   r   )rB   rC   rD   rE   r   boolra   r;   r   r   r   r   ro   r}   r   rF   r-   r,   r   r   /  sI     D
2htn 
2 
2t 
2)&
 
(r-   r   c                       e Zd ZdZddZd Zy)Zoomifyz_
    Tiles compatible with the Zoomify viewer
    ----------------------------------------
    c                 J   || _         || _        ||f}t        j                  ||z        t        j                  ||z        f}g | _        | j                  j                  |       g | _        | j                  j                  |       |d   |kD  s|d   |kD  rt        j                  |d   dz        t        j                  |d   dz        f}t        j                  |d   |z        t        j                  |d   |z        f}| j                  j                  |       | j                  j                  |       |d   |kD  r|d   |kD  r| j                  j                          | j                  j                          t        | j                        | _
        g | _        d| j                  d<   t        d| j                  dz         D ]Y  }| j                  j                  | j                  |dz
     d   | j                  |dz
     d   z  | j                  |dz
     z          [ y)z'Initialization of the Zoomify tile treer   r=   r`   N)rZ   
tileformatr   r   tierSizeInTilesappendtierImageSizefloorreverser?   numberOfTierstileCountUpToTierrl   )r:   widthheightrZ   r   	imagesizetilesrn   s           r,   r;   zZoomify.__init__  s    #$FO	59,-tyy)9K/LM  "##E*  !!),lY&)A,*BIaL1$45tzz)A,QRBR7STI		)A,23		)A,23E   ''.%%i0 lY&)A,*B 	$$&""$ !!5!56 "$$%q!q$,,q01 	A""))$$QU+A.1E1Ea!e1LQ1OO((Q/0	r-   c           
          ||| j                   |   d   z  z   | j                  |   z   }t        j                  j	                  dt        j                  |dz        z  |d|d|d| j                        S )z0Returns filename for tile with given coordinatesr   zTileGroup%.0fr   -.)r   r  r)   r+   joinr   r   r   )r:   rb   rc   rd   	tileIndexs        r,   tilefilenamezZoomify.tilefilename  sn     D003A6669O9OPQ9RR	ww||djjS991doo6
 	
r-   N)r   jpg)rB   rC   rD   rE   r;   r  rF   r-   r,   r   r     s    
&P
r-   r   c                       e Zd Zy)	GDALErrorNrN   rF   r-   r,   r  r    rO   r-   r  messagedetailsrR   c                     t         j                  j                  d       t         j                  j                  d| z         |r"t         j                  j                  d|z         t        j                  d       y )Nz4Usage: gdal2tiles.py [options] input_file [output]

zgdal2tiles.py: error: %s
z

%s
r`   )sysstderrrA   exit)r  r  s     r,   exit_with_errorr    sT     JJMNJJ1G;<

g-.HHQKr-   cache_in_bytesc                 x    dt        | dz  dz        z  t        j                  d<   t        j                  |        y )Nz%d   GDAL_CACHEMAX)ra   r)   environr   SetCacheMax)r  s    r,   set_cache_maxr    s4     #'^d-BT-I)J"JBJJ^$r-   c                    |sg }| ||c|d<   |d<   |d<   ||d<   d|vr||d<   d|vrt        |d   dz        |d<   d|vrt        |d   d	z        |d<   |g k(  rd
|d<   | 4d}	t        j                  |j                  t        j                        |d<   nEd}	t
        j                  |||      |d<   d|| |d   fz  |d<    || ||      \  |d<   |d<   |d<   |d<   | dk(  rd|z  dz   |d<   n| 	d|z  |d<   nd|d<   |j                  }
|
s|	rd}
nd}
d|z  }|	r|d|z  z  }|D ]G  \  }}} ||||      \  }}}}t
        j                  |||      }|d||||d   |||||d   |
|||fz  z  }I |dz  }|S )z6
    Template for the KML. Returns filled string.
    rg   rh   tzr   rZ   minlodpixelsr`   maxlodpixels   r   Fxml_escaped_titleT	realtiley%d/%d/%d.kmlsouthwestnortheastr   r=   	drawOrderz../../r   a.  <?xml version="1.0" encoding="utf-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
  <Document>
    <name>%(xml_escaped_title)s</name>
    <description></description>
    <Style>
      <ListStyle id="hideChildren">
        <listItemType>checkHideChildren</listItemType>
      </ListStyle>
    </Style>a  
    <Region>
      <LatLonAltBox>
        <north>%(north).14f</north>
        <south>%(south).14f</south>
        <east>%(east).14f</east>
        <west>%(west).14f</west>
      </LatLonAltBox>
      <Lod>
        <minLodPixels>%(minlodpixels)d</minLodPixels>
        <maxLodPixels>%(maxlodpixels)d</maxLodPixels>
      </Lod>
    </Region>
    <GroundOverlay>
      <drawOrder>%(drawOrder)d</drawOrder>
      <Icon>
        <href>%(realtiley)d.%(tileformat)s</href>
      </Icon>
      <LatLonBox>
        <north>%(north).14f</north>
        <south>%(south).14f</south>
        <east>%(east).14f</east>
        <west>%(west).14f</west>
      </LatLonBox>
    </GroundOverlay>
a  
    <NetworkLink>
      <name>%d/%d/%d.%s</name>
      <Region>
        <LatLonAltBox>
          <north>%.14f</north>
          <south>%.14f</south>
          <east>%.14f</east>
          <west>%.14f</west>
        </LatLonAltBox>
        <Lod>
          <minLodPixels>%d</minLodPixels>
          <maxLodPixels>-1</maxLodPixels>
        </Lod>
      </Region>
      <Link>
        <href>%s%d/%d/%d.kml</href>
        <viewRefreshMode>onRegion</viewRefreshMode>
        <viewFormat/>
      </Link>
    </NetworkLink>
        z      </Document>
</kml>
    )ra   r   EscapeStringtitle	CPLES_XML
GDAL2TilesgetYTileurl)rg   rh   r  tileextrZ   tileswneoptionschildrenargstilekmlr0  scxcyczcsouthcwestcnorthceastytiles                       r,   generate_kmlr@    sL    )+R&DJT
DJ D$%[T!"4#4q#89^T!"4#4q#89^2~!^	z$($5$5gmmT^^$T !&//B@[$2b"d;>O5P$P !CKBPRTVCW@WtF|T']DL	QwFQJ[	F[[
++CCC		 
	  	4 5	
<  &

B'/B';$vu##BG4	 ,  
+#
 #	
&
P  
 A Hr-   c                    | j                   }|j                   }|j                  }|j                  dk(  r`t        d|dz         D ]M  }t	        j
                  | j                  |      |j                  |      d      }|dk7  s>t        d||fz         O y|j                  dk(  rct        r\|j                  d      rt        d      t        j                  |||ft        j                        }	t        |      D ]7  }t        j                  | j                  |dz         dd||      |	dddd|f<   9 t!        j"                  |	d	      }
|
j%                  ||ft         j&                        }t(        j*                  j-                  |      r,t!        j.                  |      }t!        j0                  |||      }i }|j2                  d
k(  r!|j4                  rd|d<   n|j6                  |d<    |j8                  ||j2                  fi | y|j                  dk(  rt        j:                  }n@|j                  dk(  rt        j<                  }n|j                  dk(  rt        j>                  }n|j                  dk(  rt        j@                  }n|j                  dk(  rt        jB                  }n|j                  dk(  rt        jD                  }n|j                  dk(  rt        jF                  }n|j                  dk(  rt        jH                  }n_|j                  dk(  rt        jJ                  }n?|j                  dk(  rt        jL                  }n|j                  dk(  rt        jN                  }| jQ                  d|tS        |      z  ddd|tS        |      z  f       |jQ                  d       t	        jT                  | |dd      }|dk7  rt        d||fz         yy)z-Scales down query dataset to the tile datasetr   r=   r   z+RegenerateOverview() failed on %s, error %dr   r$   zDOutputting to /vsi file systems with antialias mode is not supportedNRGBAWEBPTlosslessqualityr   r   r   r   r   r   r   r   r   r   r           rF  r   rF  rF  rF  r   z'ReprojectImage() failed on %s, error %d)+RasterXSizeRasterCount
resamplingrl   r   RegenerateOverviewGetRasterBandr  numpy_availabler&   r(   numpyzerosuint8	gdalarrayBandReadAsArrayr   	fromarrayresizeLANCZOSr)   r+   existsrJ   	composite
tiledriverwebp_losslesswebp_qualitysaveGRA_NearestNeighbourGRA_Bilinear	GRA_CubicGRA_CubicSplineGRA_LanczosGRA_ModeGRA_MaxGRA_MinGRA_MedGRA_Q1GRA_Q3SetGeoTransformr   ReprojectImage)dsquerydstiler3  r  	querysizerZ   	tilebandsrn   rf   arrayimim1im0paramsgdal_resamplings                  r,   scale_query_to_tilers  d  sh    ##I""I""IY& q)a-( 	A))%%a(&*>*>q*A9C axA\SVDWW	 
		{	*""6*V 
 Y	9=u{{Ky! 	A&66%%a!e,aIyE!Q'N	 __UF+iiI.>77>>,'**\*C//#sC0C'$$%)z"$+$8$8y!w11<V< '"77O:-"//O7*"nnO=0"22O9,"..O6)"mmO5("llO5("llO5("llO4'"kkO4'"kkO 	E),,E),,		
 	=>!!'64O!89\3<OO r-   input_datasetr3  c                 V   g }|j                   rjt        t        t        |j                   j	                  d                  }t        |      | j                  k  r|| j                  z  d| j                   }n|}nt        d| j                  dz         D ]p  }| j                  |      }|j                         }|'|j                  t        j                  k(  r|t        |      k7  s
|dk  s|dkD  rg } n|j                  |       r |j                  rt         j#                  d|z         |S )zc
    Extract the NODATA values from the dataset or use the passed arguments as override if any
    ,Nr=   r      z
NODATA: %s)	srcnodatar   mapr   splitr?   rI  rl   rL  GetNoDataValueDataTyper   GDT_Bytera   r   verboseloggerdebug)rt  r3  	in_nodatandsrn   bandraster_no_datas          r,   setup_no_data_valuesr    s    I3ug//55c:;<s8m///}888:UM<U<UVIIq-33a78 	1A ..q1D!002N)==DMM1"c.&99%)%+ !#I  0	1 \I-.r-   c                    d}d}|j                   rAt        j                         }	 |j                  |j                          |j                         }n\| j                         }|s#| j                         dk7  r| j                         }|r%t        j                         }|j                  |       ||j                  t        j                         ||fS # t        $ r t        d      w xY w)z
    Determines and returns the Input Spatial Reference System (SRS) as an osr object and as a
    WKT representation

    Uses in priority the one passed in the command line arguments. If None, tries to extract them
    from the input dataset
    Nz Invalid value for --s_srs optionr   )s_srsr   r   r   RuntimeError
ValueErrorExportToWktGetProjectionGetGCPCountGetGCPProjectionImportFromWktSetAxisMappingStrategyOAMS_TRADITIONAL_GIS_ORDER)rt  r3  	input_srsinput_srs_wkts       r,   setup_input_srsr    s     IM}}((*		A&&w}}5 "--/%335!:!:!<!A)::<M,,.I##M2(()G)GHm##  	A?@@	As   C C(r  c                 n   t        j                         }|j                  dk(  r|j                  d       n^|j                  dk(  r|j                  d       n=|j                  dk(  r| }n+t        |j                     j
                  j                         }|r|j                  t         j                         |S )z2
    Setup the desired SRS (based on options)
    r   i  r     r   )	r   r   profileImportFromEPSGtmsMaprU   Cloner  r  )r  r3  
output_srss      r,   setup_output_srsr    s     %%'J*$!!$'	J	&!!$'	H	$
GOO,00668
))#*H*HIr-   datasetc                 R    | j                         dk7  xs | j                         dk7  S )NrG  r   )GetGeoTransformr  )r  s    r,   has_georeferencer  %  s/    !%CC 	& A%r-   from_datasetfrom_srsto_srsc           	         |r|st        d      |j                         |j                         k7  s| j                         dk7  r|j                         r/|j	                  d      dk(  r|j                  d      dk(  r| j                  d      }|r|d   dk(  r|d	   dk(  r|d
   dk  r|d   }|d   | j                  |d   z  z   }|d   }|d   | j                  |d
   z  z   }d}	d}
|dk  rd}d}
|dkD  rd}d}
||	kD  r|	}d}
||	 k  r|	 }d}
|
rst        j                  ||      }|j                  ||      dd \  }}|j                  ||      dd \  }}t        j                  d| d||||g|j                         d      S t        j                  | |j                         |j                               }|rA|j                   r5t"        j%                  d       |j'                         j)                  d|       |S | S )z
    Returns the input dataset in the expected "destination" SRS.
    If the dataset is already in the correct SRS, returns it unmodified
    z8from and to SRS must be defined to reproject the datasetr   NEPSG3857T)can_return_nullr`         r=   r   gIECU@F     fr   r   VRT	EPSG:3857)formatoutputBoundssrcSRSdstSRSzLWarping of the raster by AutoCreateWarpedVRT (result saved into 'tiles.vrt')z	tiles.vrt)r  ExportToProj4r  r   GetAuthorityNameGetAuthorityCoder  rH  RasterYSizer   CoordinateTransformationTransformPointr   Warpr  AutoCreateWarpedVRTr~  r  r  	GetDriver
CreateCopy)r  r  r  r3  from_gtminlonmaxlonmaxlatminlatMAX_LATadjustBoundsctr'  r&  r)  r(  
to_datasets                    r,   reproject_datasetr  ,  s9    6RSS F$8$8$::  "a' !!#''-7''-7"2242HG71:?wqzQ71:PQ>  l&>&>&KK  l&>&>&KK*$F?#F#'LE>"F#'LG#$F#'LWH$%XF#'L55hGB"$"3"3FF"CBQ"GKD%"$"3"3FF"CBQ"GKD%99$$&*E4%?'335*  --(..0&2D2D2F

 wLL^   "--k:Fr-   c                    |s| S t        j                  |       }|j                  d      }|| S |j                         D ]q  \  }}t        j                         }|j                  dd|i       |j                  |       |j                  d       |j                         }|j                  d|       s t        j                  |      j                         S )NGDALWarpOptionsOptionnamer   )r   
fromstringfinditemsTreeBuilderstartdataendcloseinserttostringdecode)
vrt_stringwarp_optionsvrt_rootr3  keyvaluetbelems           r,   add_gdal_warp_options_to_stringr  r  s    %%j1Hmm-.G"((*  
U$$&
FC=)

xxxzq$  )0022r-   warped_vrt_datasetnodata_valuesc                    |g k7  sJ | j                  d      d   }t        |ddd      }t        j                  |      }|j	                  ddj                  |D cg c]  }t        |       c}             |r[|j                  rOt        j                  d       t        d	d
      5 }|j                  |j                  d      d          ddd       |S |S c c}w # 1 sw Y   |S xY w)z^
    Takes an array of NODATA values and forces them on the WarpedVRT file dataset passed
    xml:VRTr   NO_DATAYES)	INIT_DESTUNIFIED_SRC_NODATANODATA_VALUES z/Modified warping result saved into 'tiles1.vrt'
tiles1.vrtwN)GetMetadatar  r   OpenSetMetadataItemr
  r   r~  r  r  rJ   rA   )r  r  r3  r  corrected_datasetrn   r9   s          r,   update_no_data_valuesr    s     B#//	:1=J0)5IJ$ 		*- %%="Aa3q6"AB 7??FG,$ 	AGG%11)<Q?@	A  #B	A s   C'$CC&r  c                 J   t        j                  |       }d}d}t        |      D ]L  }|j                  dk(  r2|dz  }|j	                  d      }||j
                  dk(  rt        d      |r n|dz  }N t        j                         }|j                  ddt        |dz         dd	       |j                  d
i        |j                  d       |j                  d
       |j                  d       |j                         }|j                  ||       |j	                  d      }t        j                         }|j                  di        |j                  t        |dz                |j                  d       |j                         }|j                  |       t        j                         }|j                  dddi       |j                  d       |j                  d       |j                         }|j                  |       t        j                  |      j!                         S )Nr   VRTRasterBandr=   z./ColorInterpAlphazAlpha band already presentByteVRTWarpedRasterBand)dataTyper  subClassColorInterpz.//GDALWarpOptionsDstAlphaBandr  r  r  0)r   r  r   tagr  textr(   r  r  r   r  r  r  r  r   r  r  )	r  r  indexnb_bandssubelem
color_noder  r  r  s	            r,   add_alpha_band_to_string_vrtr    s    %%j1HEH> ;;/)MH o6J%*//W*D <==
 
	 	 	"BHH1%-	
 HH]BGGGFF=FF?88:DOOE4 ==!56L		 	 	"BHH^R GGC1FF>88:D 
	 	 	"BHHX,-GGCLFF888:D)0022r-   c                 ^   | j                   dv r| j                  d      d   }t        |      }t        j                  |      } |r[|j
                  rOt        j                  d       t        dd      5 }|j                  | j                  d      d          ddd       | S | S # 1 sw Y   | S xY w)z
    Handles dataset with 1 or 3 bands, i.e. without alpha channel, in the case the nodata value has
    not been forced by options
    )r=   r   r  r   z9Modified -dstalpha warping result saved into 'tiles1.vrt'r  r  N)
rI  r  r  r   r  r~  r  r  rJ   rA   )r  r3  r  r9   s       r,   'update_alpha_value_for_non_alpha_inputsr    s     %%/'33I>qA
1*=
!YYz2wLLTUlC( FA*66yA!DEF F s   2$B""B,c                     | j                  d      j                         }|j                         t        j                  z  s| j
                  dk(  s| j
                  dk(  r| j
                  dz
  S | j
                  S )zG
    Return the number of data (non-alpha) bands of a gdal dataset
    r=   r  r`   )rL  GetMaskBandGetMaskFlagsr   	GMF_ALPHArI  )r  	alphabands     r,   nb_data_bandsr    sk     %%a(446I				!DNN	2!#!#""Q&&r-   c                 |    g }| j                   dk(  r*| j                  rdg}|S dt        | j                        z   g}|S )NrC  zLOSSLESS=TruezQUALITY=)rX  rY  r   rZ  )r3  coptss     r,   _get_creation_optionsr    sL    EV#  $%E L  #g&:&:";;<ELr-   tile_job_infoTileJobInfo
TileDetailc                 	   | j                   }| j                  }| j                  }| j                  }| j                  }|dz   }t        t        dd       }|r |j                         | j                  k(  r|}	n9t        j                  | j                  t        j                        }	|	t        _        t        j                  d      }
t        j                  | j                        }|	j                  d      j!                         }|j"                  }|j$                  }|j&                  }|j(                  }|j*                  }|j,                  }|j.                  }|j0                  }|j2                  }|j4                  }|j6                  }|j8                  }t:        j<                  j?                  |tA        |      tA        |      |d|      }|
jC                  d|||      }d x}}|jD                  r.tF        jI                  d| d| d| d| d| d| d| d| d	       |d
k7  r|d
k7  r|d
k7  r|d
k7  r}|jK                  ||||||      }| jL                  r-tO        |      |jQ                  djS                  d            k(  ry |	jK                  ||||||tU        tW        d|dz                     }|r||k(  rF|jY                  |||||tU        tW        d|dz                      |jY                  ||||||g       ni|
jC                  d|||      }|jY                  |||||tU        tW        d|dz                      |jY                  ||||||g       t[        ||||       ~~|j\                  dk7  r|j_                  ||d
ta        |             ~| jb                  rte        | |      }|t:        j<                  j?                  |tA        |      tA        |      dtf        ji                  |||      z        }|jj                  rtm        |      scto        |d      5 } | jq                  ts        |||| j                  | j                  || j                        jS                  d             d d d        y y y y # 1 sw Y   y xY w)Nr=   	cached_dsMEMr	  r   z	ReadRaster Extent: (, z), ()r    ascii	band_listr  r   strictr3  z%d.kmlwbr   ):r  output_file_pathtile_extensionrZ   r3  getattrthreadLocalGetDescriptionsrc_filer   r  GA_ReadOnlyr  GetDriverByNametile_driverrL  r   rg   rh   r  rxryrxsizerysizewxwywxsizewysizerk  r)   r+   r
  r   Creater~  r  r  
ReadRasterexclude_transparentr?   countencoder   rl   WriteRasterrs  rJ  r  r  kmlget_tile_swner.  r/  resumer2   rK   rA   r@  )!r  tile_detaildataBandsCountoutputr1  rZ   r3  rl  r  dsmem_drvout_drvr  rg   rh   r  r!  r"  r#  r$  r%  r&  r'  r(  rk  r  rj  r  alphari  swnekmlfilenamer9   s!                                    r,   create_base_tiler;    sx   "00N++F**G''I##G"I[$7IY--/=3I3IIYY}--t/?/?@ """5)G""=#<#<=G  #//1I	B	B	B	B	BFF	B	BFF%%I 77<<BRR:QRL^^B	9i@FD5$RD2$b6($rd"RDPRSYRZZ\]c\ddef	
 {v{v{v{$$RVVVVL ,,Uu{{MM'"@
 2
 }}5NQ$678  
 	!uQ(:;<   r2vvuT nnRIyIG uQ(:;<    B)U|T[(&4I'4R 	 	
 	 ]G4'',,BB:..r2w??	K >>)<[$/ 1GG$)88)33 )11 !&/
  *=   s   AQ55Q>base_tz
base_tilesoutput_folderc                 	   | dz
  }|d   d   dz	  }|d   d   dz	  }t         j                  |||      }t        j                  j	                  |t        |      t        |      |d|j                        }	|j                  rt        j                  |	       |j                  r-t        |	      r"|j                  rt        j                  d       yt        j                  d      }
|j                  }t        j                  |      }|j                  dz   }|
j!                  dd|j"                  z  d|j"                  z  |      }|
j!                  d|j"                  |j"                  |      }g }|D ]  }|d   }|d   }t         j                  || |      }t        j                  j	                  |t        |       t        |      |d|j                        }t        |      stt        j$                  |t        j&                        }|dz  dk(  rd}n|j"                  }|j(                  r'|j*                  d	k(  r|dz  dk(  rd}n$|j"                  }n|dz  dk(  r|j"                  }nd}|j,                  |dz
  k(  rx|
j/                  d|d      }|j1                          t3        d
g|j"                  |j"                  z  z        }|j5                  dd|j"                  |j"                  ||g       |}n|j,                  |k7  rt7        d      |j9                  dd|j"                  |j"                        }|j5                  |||j"                  |j"                  |t;        t=        d|dz                      |j?                  |        |sytA        ||||	       |jB                  dk7  rM|j/                  |	|dtE        |             |	dz   }t        jF                  |      t        jH                  |       |j                  r+t        j                  d|  ddj	                  |      z         |jJ                  rtM        ||      }|tO        t        j                  j	                  |d|||fz        d      5 }|jQ                  tS        ||||j                  |j"                  |||D cg c]  }|d   |d   | f c}      jU                  d             ddd       yyyc c}w # 1 sw Y   yxY w)zLGenerating an overview tile from no more than 4 underlying tiles(base tiles)r=   r   r	  +Tile generation skipped because of --resumeNr  r   r`   r   rw  r  z'Unexpected number of bands in base tiler  r   r  z.aux.xmlz	build from zoom z, tiles: %srv  r%  r  r   )+r.  r/  r)   r+   r
  r   r  r~  r  r  r1  r2   r   r  r   r  r)  rZ   r  r  xyzr  rI  r  AddBand	bytearrayr.  r(   r*  r   rl   r   rs  rJ  r  r/   Unlinkr/  r0  rK   rA   r@  r-  ) r<  r=  r>  r  r3  overview_tzoverview_txoverview_tyoverview_ty_realr  
mem_driverr   
out_driverrl  ri  rj  usable_base_tiles	base_tilebase_txbase_tybase_ty_realbase_tile_pathdsquerytiletileposxtileposytmp_dsr   	base_dataaux_xmlr9  r9   ts                                    r,   create_overview_tilerX    s    A+KQ-"a'KQ-"a'K!**;WM77<<KK#]%A%AB	L \"~~&.??LLFG%%e,J++K%%k2J++a/I
A''']-D-D)DiG 
M##]%<%<iF  @,	A,A,!**7GWELL#]%A%AB	
 n%ii0@0@AQ;!H$..H;;7??h6{a(22{a(22""i!m3**2{A>FNN00=3J3JJKD ''''$+   !K$$	1EFF**q-))=+B+B
	 	####5IM23 	 	
 	  +A@,D |L[(&4I'4R 	 	
 +==!-KK )'+>*AUUV ]G4!"k;@P%QQ    ###%44%//8BC1!A$!g.C	 fWo   & D! s   80S$(S:S$S$$S-c                    i }|j                   |    \  }}}}t        ||dz
  d      D ]E  }|dz	  }	t        ||dz         D ],  }
|
dz	  }|
|f}||	f}||vrg ||<   ||   j                  |       . G | dz
  }t        ||dz         D ]E  }
|
dz	  }t        j                  j                  |t        |      t        |            }t        |       G t        |j                               S )z6Group base tiles that belong to the same overview tiler=   r   )
tminmaxrl   r   r)   r+   r
  r   r*   r   values)r<  r>  r  overview_to_basestminxtminytmaxxtmaxyrh   rG  rg   rF  rL  overview_tilerE  tiledirnames                   r,   group_overview_base_tilesrc  C  s   
 !.!6!6w!?E5%E519b) 
?Aguqy) 	?B'KRI(+6M$5535!-0m,33I>	?
? A+KE519% Agggll=#k2BCDTU
 !((*++r-   c                     d}t        | j                  dz
  | j                  dz
  d      D ]<  }| j                  |   \  }}}}|dt	        ||z
        z   dt	        ||z
        z   z  z  }> |S )Nr   r=   r   )rl   tmaxztminzrZ  r   )r  tile_numberr  r]  r^  r_  r`  s          r,   count_overview_tilesrh  `  s    KM''!+]-@-@1-DbI K%2%:%:2%>"ueUC..1s55=7I3IJJK r-   c                     d} t        j                  | dt        z         }|j                  ddddt        dd	j                  t              z  
       |j                  ddddt        dd	j                  t              z  
       |j                  ddddd       |j                  dddd       |j                  ddddd       |j                  d d!d"d#d$       |j                  d%d&d'dd(       |j                  d)dd*d+,       |j                  d-d.dd/d0,       |j                  d1d2dd3d4,       |j                  d5d6dd7d8,       |j                  d9d:d;d<=       |j                  d>dd?d@,       |j                  dAdBdCdDd;dEF       |j                  dGdHdIdJgdIddKL       t        j                  |dMdN      }|j                  dOdPdQddR       |j                  dSdTdQdUdV       |j                  dWdXdYdZ       |j                  |       t        j                  |d[d\      }|j                  d]d^d_dt        d`d	j                  t              z  
       |j                  dadbdcdd       |j                  dedfdgdh       |j                  didjdkdl       |j                  dmdndodp       |j                  |       t        j                  |dqdr      }|j                  dsdtddu       |j                  |       t        j                  |dvdw      }|j                  dxdyt        dzd{|       |j                  d}d~dd       |j                  |       |j                  ddddddddddd       |S )z*Prepare the option parser for input (argv)z*Usage: %prog [options] input_file [output]z%prog )versionz-pz	--profiler  choicezGTile cutting profile (%s) - default 'mercator' (Google Maps compatible)rv  )desttypechoiceshelpz-rz--resamplingrJ  z*Resampling method (%s) - default 'average'z-sz--s_srsr  SRSz;The spatial reference system used for the source input data)rl  metavarro  z-zz--zoomrt   z4Zoom levels to render (format:'2-5', '10-' or '10').)rl  ro  z-ez--resumer1  
store_truez)Resume mode. Generate only missing files.)rl  actionro  z-az--srcnodatarx  NODATAz4Value in the input dataset considered as transparentz-dz--tmscompatibler   zfWhen using the geodetic profile, specifies the base resolution as 0.703125 or 2 tiles at zoom level 0.z--xyzrA  z<Use XYZ tile numbering (OSM Slippy Map tiles) instead of TMS)rs  rl  ro  z-vz	--verboser~  zPrint status messages to stdoutz-xz	--excluder+  z-Exclude transparent tiles from result tilesetz-qz--quietquietz%Disable messages and status to stdoutz--processesnb_processesra   z%Number of processes to use for tiling)rl  rm  ro  --mpimpizeAssume launched by mpiexec and ignore --processes. User should set GDAL_CACHEMAX to size per process.z
--tilesizetilesizePIXELSr   z#Width and height in pixel of a tile)rl  rq  defaultrm  ro  z--tiledriverrX  PNGrC  z&which tile driver to use for the tiles)rl  rn  r{  rm  ro  zKML (Google Earth) optionsz8Options for generated Google Earth SuperOverlay metadataz-kz--force-kmlr/  zGenerate KML for Google Earth - default for 'geodetic' profile and 'raster' in EPSG:4326. For a dataset with different projection use with caution!z-nz--no-kmlstore_falsez5Avoid automatic generation of KML files for EPSG:4326z-uz--urlr0  z?URL address where the generated tiles are going to be publishedzWeb viewer optionsz3Options for generated HTML viewers a la Google Mapsz-wz--webviewer	webviewerz+Web viewer to generate (%s) - default 'all'z-tz--titler,  zTitle of the mapz-cz--copyright	copyrightzCopyright for the mapz-gz--googlekey	googlekeyz\Google Maps API key from https://developers.google.com/maps/faq?csw=1#using-google-maps-apisz-bz	--bingkeybingkeyz6Bing Maps API key from https://www.bingmapsportal.com/zMapML optionsz Options for generated MapML filez--mapml-templatemapml_templatezFilename of a template mapml file where variables will be substituted. If not specified, the generic template_tiles.mapml file from GDAL data resources will be usedzWEBP optionszOptions for WEBP tiledriverz--webp-qualityrZ  K   z?quality of webp image, integer between 1 and 100, default is 75)rl  rm  r{  ro  z--webp-losslessrY  z+use lossless compression for the webp imageFr   Nr   r   r   INSERT_YOUR_KEY_HEREr=   )r~  r  r/  r0  r~  r  rJ  r1  r  r  	processes)optparseOptionParser__version__
add_optionprofile_listr
  resampling_listOptionGroupadd_option_groupwebviewer_listra   set_defaults)usagepgs      r,   optparse_initr  i  s    9EeX-CDALL'),,)?@  
 LL9CHH_<UU   LLJ   LLC	   LL8   LLC   LL6  	 LLK	   LL.   LL"<   LL4   LL4	   LL=	   LL2   LL5   		$B	A
 LL  
 LLD   LLN	   q 		!V	A LL:SXXn=UU   LLyw5GLHLL};=TLULLk	   LLE	   q 	Q1STALL  
 q 	Q0MNALLN   LL:	   qNN(&   Hr-   argvc                    t               }|j                  |       \  }}|st        d       t        |      dkD  rt        dddj	                  |      z         |d   }t        |      st        d|z         t        |      dk(  r|d	   }n?t        j                  j                  t        j                  j                  |            d   }|j                  d
k(  rd|_        |j                  dk(  rd|_        |rc|j                  r&t        j                   t        j"                  d       n1|j$                  s%t        j                   t        j&                  d       t)        |||      }|||fS )N)r5  zDYou need to specify at least an input file as argument to the scriptr`   z3Processing of several input files is not supported.znPlease first use a tool like gdal_vrtmerge.py or gdal_merge.py on the files: gdal_vrtmerge.py -o merged.vrt %sr  r   z:The provided input file %s does not exist or is not a filer=   r    Tr   z%(message)s)levelr  )r  
parse_argsr  r?   r
  r2   r)   r+   splitextbasenamer~  rA  r  r   r~  loggingbasicConfigDEBUGru  INFOoptions_post_processing)r  called_from_mainparserr3  r5  
input_filer>  s          r,   process_argsr  L  s>   _F%%4%0MGT R	
 4y1}A79<$H	
 aJ*H:U	
 4yA~Q (()9)9*)EFqIG#??j($(G!??gmmMJgll=I%gz=IG}g--r-   r  c                 @   | j                   s$t        j                  j                  |      | _         d }d }t	        | d      r| j
                  r}t        | j
                  t              rc| j
                  j                  dd      }|d   }t        |      }t        |      dk(  r'|d   }|r"t        |      }||k  rt        d||fz        |}||g| _        | j                  r0| j                  j                  d      s| xj                  dz  c_        | j                  rM|}|j                  d      r|d d }| xj                  t        j                  j                  |      dz   z  c_        | j                  d	k(  rt        st!        d
d       | j"                  dk(  ryt%        j&                  | j"                        t!        d       | j(                  sC| j*                  dk  s| j*                  dkD  rt!        d       t        | j*                        | _        | j,                  rt.        j1                  dt        |       z         t.        j1                  d|        t.        j1                  d|        t.        j1                  dt%        j2                         dz  dz  z         | S )Nrt   r  r=   r   r`   z%max zoom (%d) less than min zoom (%d)/r   r   z2'antialias' resampling algorithm is not available.z/Install PIL (Python Imaging Library) and numpy.rC  zWEBP driver is not availabled   z+webp_quality should be in the range [1-100]zOptions: %szInput: zOutput: zCache: %d MBr  )r,  r)   r+   r  hasattrrt   r   r   rz  ra   r?   r(   r0  endswithrJ  rM  r  rX  r   r  rY  rZ  r~  r  r  GetCacheMax)	r3  r  r>  rf  re  minmaxzoom_minzoom_maxout_paths	            r,   r  r  x  s/    ==((4 EEwGLLZc5R##C+!9Hv;!ayHH5=#?5%.P 
 E5>GL{{7;;//4s{{ S!}Hrww''1C77 [(@=	

 V# 2 23;:;$$##q(G,@,@3,F MN#&w';';#<G  ]S\12wzl+,x/0^t'7'7'9D'@4'GHINr-   c                   T    e Zd ZdZdZdZdZdZdZdZ	dZ
dZdZdZdZd Zd Zd Zd Zy)r
  r   c                 L    |D ]  }t        | |      st        | |||          ! y r7   r  setattrr:   kwargsr  s      r,   r;   zTileDetail.__init__  +     	0CtS!c6#;/	0r-   c                 V    d| j                   d| j                  d| j                  dS NzTileDetail 
rg   rh   r  r]   s    r,   __unicode__zTileDetail.__unicode__      ,0GGTWWdggFFr-   c                 V    d| j                   d| j                  d| j                  dS r  r  r]   s    r,   __str__zTileDetail.__str__  r  r-   c                 V    d| j                   d| j                  d| j                  dS r  r  r]   s    r,   __repr__zTileDetail.__repr__  r  r-   N)rB   rC   rD   rg   rh   r  r!  r"  r#  r$  r%  r&  r'  r(  rk  r;   r  r  r  rF   r-   r,   r
  r
    sU    	
B	
B	
B	
B	
BFF	
B	
BFFI0
GGGr-   c                   h    e Zd ZdZdZdZdZdZdZdZ	dZ
g ZdZdZdZg ZdZdZdZdZd Zd Zd Zd	 Zy)
r	  zC
    Plain object to hold tile job configuration for a dataset
    r   r   NFc                 L    |D ]  }t        | |      st        | |||          ! y r7   r  r  s      r,   r;   zTileJobInfo.__init__  r  r-   c                      d| j                   z  S NzTileJobInfo %s
r  r]   s    r,   r  zTileJobInfo.__unicode__      !T]]33r-   c                      d| j                   z  S r  r  r]   s    r,   r  zTileJobInfo.__str__  r  r-   c                      d| j                   z  S r  r  r]   s    r,   r  zTileJobInfo.__repr__  r  r-   )rB   rC   rD   rE   r  r  r  r  rZ   r   r/  rZ  rf  re  
in_srs_wktout_geo_transominyis_epsg_4326r3  r+  r;   r  r  r  rF   r-   r,   r	  r	    so     HMNIK
CGEEJMELG0
444r-   c                       e Zd Zy)Gdal2TilesErrorNrN   rF   r-   r,   r  r    rO   r-   r  c                       e Zd ZdedededdfdZddZddZdee	e
e   f   fd	Zdd
ZdefdZdefdZdefdZdefdZdefdZed        Zy)r.  r  r>  r3  rR   Nc                    d| _         d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _	        d| _
        d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _        |j.                  r|j.                  | _        |j0                  | _        |j0                  dk(  rd| _        nd| _        |j4                  r't7        |       t9        j:                  |      | _        nt9        j:                         | _        t>        j@                  jC                  | j<                  tE        tG                     dz         | _$        d| _%        d	| j,                  z  | _&        d
| _'        || _        || _        || _(        | jP                  jR                  dk(  r| j,                  | _&        n-| jP                  jR                  dk(  r| j,                  dz  | _&        | jP                  jT                  \  | _+        | _,        | jP                  jZ                  | _-        y)z%Constructor function - initializationNr   r|  pngwebp)dirz.vrtTr  Fr   r   r`   ).r7  r6  warped_input_datasetout_srs
nativezoomrZ  tsizer   r   r3  out_gtr2  r9  ominxomaxxomaxyr  r  r>  
isepsg4326in_srsr  rZ   ry  rX  r1  rx  r*   tempfilemkdtemptmp_dirr)   r+   r
  r   r
   tmp_vrt_filenamescaledqueryrk  overviewqueryr3  rJ  rt   rf  re  r/  )r:   r  r>  r3  s       r,   r;   zGDAL2Tiles.__init__  s   $(!
"	



! $--DN!,,& DL!DL;;]##++>DL#++-DL "T\\3uw<&;P Q   T^^+
 #$*<<""f,!^^DN\\$$
2!^^a/DN!%!2!2
DJ <<##r-   c                 &'    t        j                          t        j                   j                         _        t        j                  d       _         j                  st        d j                  z         j
                  st        d       j                  r/t        j                   j                  t         j                        }nt        d       j                  j                  r9t        j                  d|j                  |j                  |j                   fz         |st#        d j                  z         |j                   dk(  rt#        d j                  z         |j%                  d	      j'                         rt#        d
d j                  z         |j%                  d	      j(                  t         j*                  k7  rt#        dd j                  z         t-        | j                        } j                  j                  r9t        j                  d|j                  |j                  |j                   fz         t/        | j                        \   _         _        t5         j0                   j                         _        d _         j                  j:                  dk7  rf j0                  st#        dd       t=        |      st#        dd        j0                  j?                          j6                  j?                         k7  s|jA                         dk7  rvtC        | j0                   j6                         _        |r(tE         j8                  | j                         _        n&tG         j8                   j                         _         j8                  rm j                  j                  rWt        j                  d j8                  j                   j8                  j                   j8                  j                   fz          j8                  s| _        t        j                  d      jI                   jJ                   j8                         tM         j8                         _'        d _(        tS        jT                         }|jW                  d       |jY                  tR        jZ                          j6                  r||j?                          j6                  j?                         k(  rQd _(         j\                  d _.         j\                  r+ j                  j                  rt        j                  d        j\                  d _.         j8                  j_                          _0         j`                  d    j`                  d   fdk7  rt#        d        j`                  d    _1         j`                  d    j8                  j                   j`                  d	   z  z    _2         j`                  d     _3         j`                  d     j8                  j                   j`                  d	   z  z
   _4         j                  j                  rNt        j                  d!tk         jb                  d"       jh                   jd                   jf                  fz          j                  j:                  d#k(  r-tm         jn                  $       _8         jp                  jr                   _:        tw        ty        dtz                     _>        ty        dtz              D ]  } jp                  j                   jb                   jh                  |      \  }} jp                  j                   jd                   jf                  |      \  }}t        d|      t        d|      }}t        d|z  d	z
  |      t        d|z  d	z
  |      }}||||f j|                  |<     j                  x jp                  j                   j`                  d	   t         j8                  j                   j8                  j                        z  t         jn                        z         _B         j                  R jp                  j                   j`                  d	          _E        t         j                   j                         _E        t         j                   j                         _B         j                  j                  rt        j                  d%t         jp                  j                   jb                   jh                              t         jp                  j                   jd                   jf                                     t        j                  d& j                  z         t        j                  d' j                   jp                  j                   j                        fz         yy j                  j:                  d(k(  rt         j                  j                   jn                  $       _K         j                  jr                   _:        tw        ty        dtz                     _>        ty        dtz              D ]  } j                  j                   jb                   jh                  |      \  }} j                  j                   jd                   jf                  |      \  }}t        d|      t        d|      }}t        d|d	z   z  d	z
  |      t        d|z  d	z
  |      }}||||f j|                  |<     j                  x j                  j                   j`                  d	   t         j8                  j                   j8                  j                        z  t         jn                        z         _B         j                  R j                  j                   j`                  d	          _E        t         j                   j                         _E        t         j                   j                         _B         j                  j                  rEt        j                  d) jb                   jh                   jd                   jf                  fz         yy j                  j:                  dk(  rd* }	t        dt        t        t        j                   |	 j8                  j                  t         jn                        z              t        j                   |	 j8                  j                  t         jn                        z                                 _P         j                  j                  r"t        j                  d+ j                  z          j                  d _B         j                  8 j                   _E        t         j                   j                         _E        n( j                   j                  kD  rd	 j                   j                  z
  z  }
 j                  j                  d,v rd-}n1 j                  j                  d.v r j                  j                  }nd/}t        j                   jJ                  | j8                  j                  |
z   j8                  j                  |
z  |0       t        j                   jJ                         _         j8                  j_                          _0         j                   _P        tw        ty        d j                  d	z                _>        tw        ty        d j                  d	z                _S        ty        d j                  d	z         D ]  }d1 j                  |z
  z   jn                  z  }d\  }}t        t        j                   j8                  j                  |z              d	z
  }t        t        j                   j8                  j                  |z              d	z
  }t        j                  |       j                  |<   ||||f j|                  |<     j\                  r: j2                  r.tS        j                   j0                  |       fd2}| _:        yd3  _:        yt         j                  j:                     }d _:        tw        ty        d|j                  d	z                _>        ty        d|j                  d	z         D ]  }|j                   jb                   jh                  | jn                        \  }}|j                   jd                   jf                  | jn                        \  }}t        d|      t        d|      }}t        |j                  d|z  z  d	z
  |      t        |j                  d|z  z  d	z
  |      }}||||f j|                  |<     j                  y|j                   j`                  d	   t         j8                  j                   j8                  j                        z  t         jn                        z   jn                         _B         j                  S|j                   j`                  d	    jn                         _E        t         j                   j                         _E        t         j                   j                         _B         j                  j                  rt        j                  d4 jb                   jh                   jd                   jf                  fz         t        j                  d& j                  z         t        j                  d5 j                  z         yy)6z=Initialization of the input raster, reprojection if necessaryr  zBThe '%s' driver was not found, is it available in this GDAL build?zCThe 'MEM' driver was not found, is it available in this GDAL build?zNo input file was specifiedz"Input file: (%dP x %dL - %d bands)z/It is not possible to open the input file '%s'.r   z"Input file '%s' has no raster bandr=   zFPlease convert this file to RGB/RGBA and run gdal2tiles on the result.zFrom paletted file you can create RGBA file (temp.vrt) by:
gdal_translate -of vrt -expand rgba %s temp.vrt
then run:
gdal2tiles temp.vrtzCPlease convert this file to 8-bit and run gdal2tiles on the result.zsTo scale pixel values you can use:
gdal_translate -of VRT -ot Byte -scale %s temp.vrt
then run:
gdal2tiles temp.vrtz(Preprocessed file:(%dP x %dL - %d bands)Nr   zInput file has unknown SRS.zEUse --s_srs EPSG:xyz (or similar) to provide source reference system.z|There is no georeference - neither affine transformation (worldfile) nor GCPs. You can generate only 'raster' profile tiles.zEither gdal2tiles with parameter -p 'raster' or use another GIS software for georeference e.g. gdal_transform -gcp / -a_ullr / -a_srs)r3  z0Projected file: tiles.vrt (%dP x %dL - %d bands)r  Fr  TzKML autotest OK!r`   r  r   r   znGeoreference of the raster contains rotation or skew. Such raster is not supported. Please use gdalwarp first.r   z#Bounds (output srs): %f, %f, %f, %f   r   r   zBounds (latlong): %s, %szMinZoomLevel: %dzMaxZoomLevel: %d (%f)r   z Bounds (latlong): %f, %f, %f, %fc                 X    t        j                  |       t        j                  d      z  S r_   )r   log10)rb   s    r,   log2z#GDAL2Tiles.open_input.<locals>.log2a	  s    zz!}tzz!}44r-   zNative zoom of the raster: %d)r   r   r   )r   r   r   r   r   r   r   )r  r  resampleAlgr   c                 &   d	j                   |z
  z  	j                  d   z  }	j                  d   | 	j                  z  |z  z   }|	j                  |z  z   }	j                  j                  r2	j
                  |	j                  z  |z  z
  }|	j                  |z  z
  }n1	j                  |	j                  z  |z  z   }|	j                  |z  z   }	j                  s0j                  ||      d d \  }}j                  ||      d d \  }}||||fS )Nr`   r=   r   )	re  r  rZ   r3  rA  r  r  r  r  )
rb   rc   rd   
pixelsizexr'  r)  r(  r&  r  r:   s
           r,   rastertileswnez-GDAL2Tiles.open_input.<locals>.rastertileswne	  s   djj1n-A>   ;;q>A,>,KKD$..:"==D||'' $

Q-?*-L L %(C C $

Q-?*-L L %(C C??&(&7&7e&DRa&He&(&7&7e&DRa&He $t33r-   c                      yN)r   r   r   r   rF   rb   rc   rd   s      r,   <lambda>z'GDAL2Tiles.open_input.<locals>.<lambda>	      r-   zBounds (georef): %f, %f, %f, %fzMaxZoomLevel: %d)Zr   AllRegisterr  rX  r7  r6  r(   r  r  r  r3  r~  r  r  rH  r  rI  r  rL  GetRasterColorTabler|  r}  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r3  r  r   r   r  r  r  r/  r  r  r  r  r  r  roundr   rZ   r   r   r2  r   rl   r   rZ  r   r   r   rf  ro   r   re  r   r   r   r   r   r   r   ra   r   r   r  rJ  	Translater  r  r  r\   ri   rX   rY   )r:   rt  r  srs4326r  r]  r^  r_  r`  r  oversample_factorr  r  r  r   r  s   `              @r,   
open_inputzGDAL2Tiles.open_inputI  s|   ++DOO<++E2||T//"  ||U  ??*.))DOOTEUEU*VM9::<<LL4!--!--!-- ADOOS
 $$)@4??RS&&q)==?X& )-8 &&q)22dmmCU& )-8 )E	<<LL:!--!--!-- (7}dll'S$T_'T\\B
 %)!<<8+;;1[
 $M2N\ ))+t||/I/I/KK))+q0,=!4;;-) 0E119dll1D- 1X114<<1D- ((T\\-A-AF11==11==11== (((5D%U#..!!4#<#<	
 ,D,E,EF  &&(t$&&s'E'EF<<G113t||7Q7Q7SS"DOxxxxDLL00/088DH //??A
 KKNDKKN+v5K [[^
KKNT66BBT[[QR^SS 	
 [[^
KKNT66BBT[[QR^SS 	

 <<LL5R($**djj$**MN <<:-*T^^DDM !MM::DM  a 67DLA|, @#}}99$**djjRTUu#}}99$**djjRTUu"1e}c!Umu"1b519e4c!R%!)U6Ku$)5%#?R @ zz!!]];;KKN11==11==
 DNN+,
 zz!!]];;DKKNK
 TZZ8
TZZ4DJ||##.44TZZLM44TZZLM
 /$**<=+zz4==#;#;DJJ#GHI $ \\!!Z/***dnnDM
 !MM::DM  a 67DLA|, @#}}99$**djjRTUu#}}99$**djjRTUu"1e}c!Umu"1a=1#4e<c!R%!)U>Su$)5%#?R @ zz!!]];;KKN11==11==
 DNN+,
 zz!!]];;DKKNK
 TZZ8
TZZ4DJ||##6zz4::tzz4::FG $ \\!!X-5 "		  $ 9 9 E E"'"7!8 		  $ 9 9 E E"'"7!8DO( ||##<tNO zz!
 zz!!__
 TZZ8
doo- %&$**t*F$G!<<**.FF"+K\\,, 1  #',,"9"9K",K))!33??BSS44@@CTT + -1IId6K6K,L)"77GGI"&**  aa 89DLeAtzzA~67DJAtzzA~. 
@" 45F#u		$";";"G"G%"OPQTUU  		$";";"G"G%"OPQTUU  "&5!1

2$)5%#?R 
@ xxDOO11$++wG4$ !/ < --.C !DM  a1)< =>DLAs23 @"99JJ

B u  #99JJ

B u  #1e}c!Umu"3#3#3ae#;a#?G%%2-15Ju %*5%#?R @ zz! 11KKN11==11==
 DNN+, NN
 zz! 11$++a.$..Q
 TZZ8
TZZ4DJ||##5zz4::tzz4::FG /$**<=/$**<= $r-   c                    t        | j                         | j                  j                  dk(  rU| j                  j                  | j                  | j                        \  }}| j                  j                  | j                  | j                        \  }}t        d|      t        d|      }}t        d|      t        d|      }}||||f| _        | j                  j                  dv r| j                  j                  dk(  r| j                  j                  r3t        t         j"                  j%                  | j                  d            skt'        t         j"                  j%                  | j                  d      d      5 }|j)                  | j+                         j-                  d	             d
d
d
       | j                  j                  dv r| j                  j                  r4t        t         j"                  j%                  | j                  d            sMt'        t         j"                  j%                  | j                  d      d      5 }|j)                  | j/                         j-                  d	             d
d
d
       n| j                  j                  dk(  rl| j                  | j                  }}| j                  | j                  }}t        d|      t        d|      }}t        d|      t        d|      }}||||f| _        n\| j                  j                  dk(  r<| j                  | j                  }}| j                  | j                  }}||||f| _        nd
| _        | j                  j                  dv r| j                  j                  r3t        t         j"                  j%                  | j                  d            skt'        t         j"                  j%                  | j                  d      d      5 }|j)                  | j1                         j-                  d	             d
d
d
       | j                  j2                  s| j                  | j                  j                  r3t        t         j"                  j%                  | j                  d            skt'        t         j"                  j%                  | j                  d      d      5 }|j)                  | j5                         j-                  d	             d
d
d
       | j                  j                  dv r| j                  j2                  r| j                  j                  dk7  r| j                  j                  dk7  s| j                  j6                  r| j                  j                  r3t        t         j"                  j%                  | j                  d            skt'        t         j"                  j%                  | j                  d      d      5 }|j)                  | j9                         j-                  d	             d
d
d
       | j:                  ra| j<                  Sg }| j>                  | j@                     \  }}}	}
tC        ||	dz         D ]4  }tC        ||
dz         D ]   }|jE                  ||| j@                  g       " 6 | j:                  r| j                  j                  r3t        t         j"                  j%                  | j                  d            st'        t         j"                  j%                  | j                  d      d      5 }|j)                  tG        d
d
d
| jH                  | jJ                  | j<                  | j                  |      j-                  d	             d
d
d
       y
y
y
y
y
# 1 sw Y   xY w# 1 sw Y   SxY w# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   y
xY w)z
        Generation of main metadata files and HTML viewers (metadata related to particular
        tiles are generated during the tile processing).
        r   g ECUr  g ECU@r   )r   r   zgooglemaps.htmlr  r   N)r   r   zleaflet.htmlr   g     Vg     V@r   )r   r   zopenlayers.htmlztilemapresource.xml)r   r    zmapml.mapmlr=   zdoc.kml)&r*   r>  r3  r  r   r   r  r  r  r  r   r   r9  r~  r1  r2   r)   r+   r
  rK   rA   generate_googlemapsr-  generate_leafletgenerate_openlayersrA  generate_tilemapresourcer   generate_mapmlr/  r2  rZ  rf  rl   r   r@  r1  rZ   )r:   r&  r'  r(  r)  r9   r4  xminyminxmaxymaxrb   rc   s                r,   generate_metadatazGDAL2Tiles.generate_metadata	  s.    	##$<<:---66tzz4::NKE4--66tzz4::NKE4lE2C4E4Ek513ud3C4EeT2DI &&*;;LL((J6||**&GGLL!3!35FG3 !T%7%79JKT L 8 8 : A A' JKL ||%%);;||**&GGLL!3!3^D3 !T%7%7H$ I 5 5 7 > >w GHI I
 \\!!Z/**djj%D**djj%DeU+S->4EdE*Ct,<4EeT2DI\\!!X-**djj%D**djj%DeT2DI DI <<!!%::<<&&fT//1BC/ GGLL!3!35FG HGGD446==gFGH   		%LL''bggll4+=+=?TUV T//1FG I557>>wGHI LL""&66  $$0%%3t||7Q7QLL''bggll4+=+=}MN d&8&8-H$O ?ST++-44W=>? 881 H%)\\$**%="D$d4* 8tTAX. 8AOOQ4::$6788 xx||**&GGLL!3!3Y?3 !T%7%7CT ( $ $ $ $ $ $ $ (	 %fWo 3  28OL LI I8H HI I ? ?  sI   ?/^"/^/;/^</_	</_<A_#"^,/^9<_	__ #_,c                    | j                   j                  st        j                  d       | j                   j                  rTt        j                  d       t        j                  d       t        j                  d       t        j                  d       | j                  | j                     \  }}}}| j                  }| j                  dz   }| j                  }| j                   j                  r:t        j                  d| j                  z         t        j                  d|z         dt        ||z
        z   dt        ||z
        z   z  }d}	g }
| j                  }t        ||dz         D ]J  }t        j                  j                  | j                   t#        |      t#        |            }t%        |       L t        ||dz
  d	      D ]  }t        ||dz         D ]  }|	dz  }	t&        j)                  ||| j                         }t        j                  j                  | j                   t#        |      t#        |      |d
| j*                        }| j                   j                  rt        j                  d|	||fz         | j                   j,                  r7t/        |      r,| j                   j                  rt        j                  d       | j                   j0                  dk(  r| j2                  j5                  |||      }n| j                   j0                  dk(  r| j6                  j5                  |||      }nR| j                   j0                  dk7  r9t8        | j                   j0                     j5                  |||| j:                        }| j                   j0                  dk7  r| j=                  |d   |d   |d   |d         \  }}|d   |d   z   }| j                   j                  rt        j                  d| d| d|        | j=                  ||d   |d   |d   |d   |      \  }}|\  }}}}|\  }}}}nt?        | j@                  |         }| j                  jB                  }| j                  jD                  }| j:                  }||z  }d}||k(  r||z  }|dk(  r|}||z  }d}||k(  r||z  }|dk(  r|}d\  }}t?        |tG        |      z  | j:                  z        }t?        |tG        |      z  | j:                  z        }| j                   jH                  s)|||z  z
  |z
  }|| j:                  k7  r| j:                  |z
  }|
jK                  tM        ||||||||||||               tO        d(i d| jP                  d| j                  d| j                   d| j*                  d| jR                  d| j:                  d| jT                  d| j                  d | jV                  d!| j                  d"| jX                  d#| jZ                  d$| j\                  d%| j^                  d&| j                   d'| j                   j`                  } | |
fS ))zi
        Generation of the base tiles (the lowest in the pyramid) directly from the input raster
        zGenerating Base Tiles:r   z(Tiles generated from the max zoom level:z(----------------------------------------r=   zdataBandsCount: %dztilebands: %dr   r   r	  z%d / %d, %sr@  r   r   r   r   r`   z	Native Extent (querysize z): r  )rk  r  )rg   rh   r  r!  r"  r#  r$  r%  r&  r'  r(  rk  r  r  r  r  r   rZ   r/  rZ  rf  re  r  r  r  r  r3  r+  rF   )1r3  ru  r  infor~  r  rZ  re  r  r3  rk  r   rl   r)   r+   r
  r>  r   r*   r.  r/  r1  r1  r2   r  r   r}   r   r  rZ   	geo_queryra   r  rH  r  r   rA  r   r
  r	  r  rX  r/  rf  r  r  r  r  r+  )!r:   r]  r^  r_  r`  r5  rl  rk  tcounttitile_detailsr  rg   rb  rh   r?  r  r   r   r  
nativesizer!  r"  r#  r$  r%  r&  r'  r(  r  xsizeysizeconfs!                                    r,   generate_base_tileszGDAL2Tiles.generate_base_tilesw
  s   
 ||!!KK01<<LLLLCDLLCDLL &*\\$**%="ueU&&''!+	NN	<<LL-0C0CCDLL945c%%-((QUU]1C-CDZZ uqy) 	"B'',,t'9'93r7CGLK[!	" uqy"- e	BE519- da"++BDLLA!ww||&&GG$dll3	  <<''LL"fl1K!KL<<&&6,+?||++%RS<<'':500R<A\\))Z700R<A\\))X5t||334??BDNNA <<''83!^^B!adAaD!A$GFB "$AAJ||++9*SBrdS
 "^^AaD!A$!adi , FB .0*BFF-/*BFF  

2E 11==  !55AAE $IeBFU{!&{!&eBFU{!&{!&!FB %,!6!GHF %,!6!GHF<<++"b5j1F:!T^^3!%&!8B ## %%%%"+kde	N  
**
--
 "//
  <<	

 
 nn
 
 LL
 **
 **
 
 ++
 **
 
 LL
  !% @ @!
& \!!r-   c                    |j                         }t        ||d   z
  |d   z  dz         }t        ||d   z
  |d   z  dz         }	t        dt        ||z
  |d   z  dz               }
t        dt        ||z
  |d   z  dz               }|s|
|}}n||}}d}|dk  rIt        |      }t        |t	        |      |
z  z        }||z
  }|
t        |
t	        |      |
z  z        z
  }
d}||
z   |j
                  kD  r6t        |t	        |j
                  |z
        |
z  z        }|j
                  |z
  }
d}|	dk  rIt        |	      }t        |t	        |      |z  z        }||z
  }|t        |t	        |      |z  z        z
  }d}	|	|z   |j                  kD  r6t        |t	        |j                  |	z
        |z  z        }|j                  |	z
  }||	|
|f||||ffS )as  
        For given dataset and query in cartographic coordinates returns parameters for ReadRaster()
        in raster coordinates and x/y shifts (for border tiles). If the querysize is not given, the
        extent is returned in the native resolution of dataset ds.

        raises Gdal2TilesError if the dataset does not contain anything inside this geo_query
        r   r=   gMbP?r   r  g      ?)r  ra   r   r   r   rH  r  )r:   r5  ulxulylrxlryrk  geotranr!  r"  r#  r$  r'  r(  r%  rxshiftr&  ryshifts                     r,   r  zGDAL2Tiles.geo_query  s    $$&#
"gaj0589#
"gaj0589QS3Y'!*4s:;<QS3Y'!*4s:;<#VFF&	FF 6"gGVuW~678Bb[Fc&E'NV,C"DEEFB;'5")<#=#FGHF^^b(F6"gGVuW~678Bb[Fc&E'NV,C"DEEFB;'5")<#=#FGHF^^b(FB'"b&&)AAAr-   c                 F   i }t        j                  | j                  j                  t         j                        |d<   | j
                  \  |d<   |d<   |d<   |d<   | j                  |d<   | j                  |d<   | j                  j                  |d<   | j                  j                  |d	<   | j                  j                  d
k(  rd|d<   n~| j                  j                  dk(  rd|d<   n_| j                  j                  r| j                  j                  |d<   n/| j                  r| j                  j                         |d<   nd|d<   d|z  }t        | j                  | j                  dz         D ]  }| j                  j                  dk(  r0|d|d   |d| j                   |z
  z  | j"                  d   z  |fz  z  }L| j                  j                  d
k(  r|d|d   |dd|z  z  |fz  z  }{| j                  j                  dk(  s|d|d   |dd|z  z  |fz  z  } |dz  }|S )z
        Template for tilemapresource.xml. Returns filled string. Expected variables:
          title, north, south, east, west, isepsg4326, projection, publishurl,
          zoompixels, tile_size, tileformat, profile
        r#  r&  r'  r(  r)  rZ   r   
publishurlr  r   r  rU   r   z	EPSG:4326r   a	  <?xml version="1.0" encoding="utf-8"?>
    <TileMap version="1.0.0" tilemapservice="http://tms.osgeo.org/1.0.0">
      <Title>%(xml_escaped_title)s</Title>
      <Abstract></Abstract>
      <SRS>%(srs)s</SRS>
      <BoundingBox minx="%(west).14f" miny="%(south).14f" maxx="%(east).14f" maxy="%(north).14f"/>
      <Origin x="%(west).14f" y="%(south).14f"/>
      <TileFormat width="%(tile_size)d" height="%(tile_size)d" mime-type="image/%(tileformat)s" extension="%(tileformat)s"/>
      <TileSets profile="%(profile)s">
r=   r   zB        <TileSet href="%s%d" units-per-pixel="%.14f" order="%d"/>
r`   g\mEAg     ?z%      </TileSets>
    </TileMap>
    )r   r+  r3  r,  r-  r9  rZ   r1  r0  r  r  r  r  rl   rf  re  r  r  )r:   r5  r7  rd   s       r,   r  z#GDAL2Tiles.generate_tilemapresourceD  s=    $($5$5LL%
 ! DH99@WtF|T']DL NN[!\\\!\\--\,,..Y<<:-%DK\\!!Z/%DK\\,,,,DK\\,,224DKDK	 
 	
 tzz4::>2 	A||##x/]\*t23dkk!nD	 %%3]L)1kAqD.@!DE %%3]L)1hAoqAB#	* 	
  	 r-   c                 N   i }t        j                  | j                  j                  t         j                        |d<   d|d<   | j                  j
                  dk7  r*|dxx   d| j                  j
                  z   z  cc<   d|d<   nd|d<   | j                  \  |d	<   |d
<   |d<   |d<   | j                  |d<   | j                  |d<   | j                  |d<   | j                  |d<   | j                  j                  |d<   | j                  j                  |d<   d|d<   d|d<   d|z  }|S )a  
        Template for googlemaps.html implementing Overlay of tiles for 'mercator' profile.
        It returns filled string. Expected variables:
        title, googlemapskey, north, south, east, west, minzoom, maxzoom, tile_size, tileformat,
        publishurl
        r#  z'https://maps.googleapis.com/maps/api/jsgooglemapsurlr  z?key=r   googlemapsurl_hintz`<!-- Replace URL below with https://maps.googleapis.com/maps/api/js?key=INSERT_YOUR_KEY_HERE -->r&  r'  r(  r)  minzoommaxzoomrZ   r   r  r  a  
// Beginning of https://github.com/gavinharriss/google-maps-v3-opacity-control/blob/master/CustomTileOverlay.js
// with CustomTileOverlay.prototype.getTileUrl() method customized for gdal2tiles needs.

/*******************************************************************************
Copyright (c) 2010-2012. Gavin Harriss
Site: http://www.gavinharriss.com/
Originally developed for: http://www.topomap.co.nz/
Licences: Creative Commons Attribution 3.0 New Zealand License
http://creativecommons.org/licenses/by/3.0/nz/
******************************************************************************/

CustomTileOverlay = function (map, opacity) {
    this.tileSize = new google.maps.Size(256, 256); // Change to tile size being used

    this.map = map;
    this.opacity = opacity;
    this.tiles = [];

    this.visible = false;
    this.initialized = false;

    this.self = this;
}

CustomTileOverlay.prototype = new google.maps.OverlayView();

CustomTileOverlay.prototype.getTile = function (p, z, ownerDocument) {
    // If tile already exists then use it
    for (var n = 0; n < this.tiles.length; n++) {
        if (this.tiles[n].id == 't_' + p.x + '_' + p.y + '_' + z) {
            return this.tiles[n];
        }
    }

    // If tile doesn't exist then create it
    var tile = ownerDocument.createElement('div');
    var tp = this.getTileUrlCoord(p, z);
    tile.id = 't_' + tp.x + '_' + tp.y + '_' + z
    tile.style.width = this.tileSize.width + 'px';
    tile.style.height = this.tileSize.height + 'px';
    tile.style.backgroundImage = 'url(' + this.getTileUrl(tp, z) + ')';
    tile.style.backgroundRepeat = 'no-repeat';

    if (!this.visible) {
        tile.style.display = 'none';
    }

    this.tiles.push(tile)

    this.setObjectOpacity(tile);

    return tile;
}

// Save memory / speed up the display by deleting tiles out of view
// Essential for use on iOS devices such as iPhone and iPod!
CustomTileOverlay.prototype.deleteHiddenTiles = function (zoom) {
    var bounds = this.map.getBounds();
    var tileNE = this.getTileUrlCoordFromLatLng(bounds.getNorthEast(), zoom);
    var tileSW = this.getTileUrlCoordFromLatLng(bounds.getSouthWest(), zoom);

    var minX = tileSW.x - 1;
    var maxX = tileNE.x + 1;
    var minY = tileSW.y - 1;
    var maxY = tileNE.y + 1;

    var tilesToKeep = [];
    var tilesLength = this.tiles.length;
    for (var i = 0; i < tilesLength; i++) {
        var idParts = this.tiles[i].id.split("_");
        var tileX = Number(idParts[1]);
        var tileY = Number(idParts[2]);
        var tileZ = Number(idParts[3]);
        if ((
                (minX < maxX && (tileX >= minX && tileX <= maxX))
                || (minX > maxX && ((tileX >= minX && tileX <= (Math.pow(2, zoom) - 1)) || (tileX >= 0 && tileX <= maxX))) // Lapped the earth!
            )
            && (tileY >= minY && tileY <= maxY)
            && tileZ == zoom) {
            tilesToKeep.push(this.tiles[i]);
        }
        else {
            delete this.tiles[i];
        }
    }

    this.tiles = tilesToKeep;
};

CustomTileOverlay.prototype.pointToTile = function (point, z) {
    var projection = this.map.getProjection();
    var worldCoordinate = projection.fromLatLngToPoint(point);
    var pixelCoordinate = new google.maps.Point(worldCoordinate.x * Math.pow(2, z), worldCoordinate.y * Math.pow(2, z));
    var tileCoordinate = new google.maps.Point(Math.floor(pixelCoordinate.x / this.tileSize.width), Math.floor(pixelCoordinate.y / this.tileSize.height));
    return tileCoordinate;
}

CustomTileOverlay.prototype.getTileUrlCoordFromLatLng = function (latlng, zoom) {
    return this.getTileUrlCoord(this.pointToTile(latlng, zoom), zoom)
}

CustomTileOverlay.prototype.getTileUrlCoord = function (coord, zoom) {
    var tileRange = 1 << zoom;
    var y = tileRange - coord.y - 1;
    var x = coord.x;
    if (x < 0 || x >= tileRange) {
        x = (x % tileRange + tileRange) % tileRange;
    }
    return new google.maps.Point(x, y);
}

// Modified for gdal2tiles needs
CustomTileOverlay.prototype.getTileUrl = function (tile, zoom) {

      if ((zoom < mapMinZoom) || (zoom > mapMaxZoom)) {
          return "https://gdal.org/resources/gdal2tiles/none.png";
      }
      var ymax = 1 << zoom;
      var y = ymax - tile.y -1;
      var tileBounds = new google.maps.LatLngBounds(
          fromMercatorPixelToLatLng( new google.maps.Point( (tile.x)*256, (y+1)*256 ) , zoom ),
          fromMercatorPixelToLatLng( new google.maps.Point( (tile.x+1)*256, (y)*256 ) , zoom )
      );
      if (mapBounds.intersects(tileBounds)) {
          return zoom+"/"+tile.x+"/"+tile.y+".png";
      } else {
          return "https://gdal.org/resources/gdal2tiles/none.png";
      }

}

CustomTileOverlay.prototype.initialize = function () {
    if (this.initialized) {
        return;
    }
    var self = this.self;
    this.map.overlayMapTypes.insertAt(0, self);
    this.initialized = true;
}

CustomTileOverlay.prototype.hide = function () {
    this.visible = false;

    var tileCount = this.tiles.length;
    for (var n = 0; n < tileCount; n++) {
        this.tiles[n].style.display = 'none';
    }
}

CustomTileOverlay.prototype.show = function () {
    this.initialize();
    this.visible = true;
    var tileCount = this.tiles.length;
    for (var n = 0; n < tileCount; n++) {
        this.tiles[n].style.display = '';
    }
}

CustomTileOverlay.prototype.releaseTile = function (tile) {
    tile = null;
}

CustomTileOverlay.prototype.setOpacity = function (op) {
    this.opacity = op;

    var tileCount = this.tiles.length;
    for (var n = 0; n < tileCount; n++) {
        this.setObjectOpacity(this.tiles[n]);
    }
}

CustomTileOverlay.prototype.setObjectOpacity = function (obj) {
    if (this.opacity > 0) {
        if (typeof (obj.style.filter) == 'string') { obj.style.filter = 'alpha(opacity:' + this.opacity + ')'; }
        if (typeof (obj.style.KHTMLOpacity) == 'string') { obj.style.KHTMLOpacity = this.opacity / 100; }
        if (typeof (obj.style.MozOpacity) == 'string') { obj.style.MozOpacity = this.opacity / 100; }
        if (typeof (obj.style.opacity) == 'string') { obj.style.opacity = this.opacity / 100; }
    }
}

// End of https://github.com/gavinharriss/google-maps-v3-opacity-control/blob/master/CustomTileOverlay.js
custom_tile_overlay_jsa)  
// Beginning of https://github.com/gavinharriss/google-maps-v3-opacity-control/blob/master/ExtDraggableObject.js

/**
 * @name ExtDraggableObject
 * @version 1.0
 * @author Gabriel Schneider
 * @copyright (c) 2009 Gabriel Schneider
 * @fileoverview This sets up a given DOM element to be draggable
 *     around the page.
 */

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Sets up a DOM element to be draggable. The options available
 *     within {@link ExtDraggableObjectOptions} are: top, left, container,
 *     draggingCursor, draggableCursor, intervalX, intervalY,
 *     toleranceX, toleranceY, restrictX, and restrictY.
 * @param {HTMLElement} src The element to make draggable
 * @param {ExtDraggableObjectOptions} [opts] options
 * @constructor
 */
function ExtDraggableObject(src, opt_drag) {
  var me = this;
  var event_ = (window["GEvent"]||google.maps.Event||google.maps.event);
  var opt_drag_=opt_drag||{};
  var draggingCursor_ = opt_drag_.draggingCursor||"default";
  var draggableCursor_ = opt_drag_.draggableCursor||"default";
  var moving_ = false, preventDefault_;
  var currentX_, currentY_, formerY_, formerX_, formerMouseX_, formerMouseY_;
  var top_, left_;
  var mouseDownEvent_, mouseUpEvent_, mouseMoveEvent_;
  var originalX_, originalY_;
  var halfIntervalX_ = Math.round(opt_drag_.intervalX/2);
  var halfIntervalY_ = Math.round(opt_drag_.intervalY/2);
  var target_ = src.setCapture?src:document;

  if (typeof opt_drag_.intervalX !== "number") {
    opt_drag_.intervalX = 1;
  }
  if (typeof opt_drag_.intervalY !== "number") {
    opt_drag_.intervalY = 1;
  }
  if (typeof opt_drag_.toleranceX !== "number") {
    opt_drag_.toleranceX = Infinity;
  }
  if (typeof opt_drag_.toleranceY !== "number") {
    opt_drag_.toleranceY = Infinity;
  }

  mouseDownEvent_ = event_.addDomListener(src, "mousedown", mouseDown_);
  mouseUpEvent_ = event_.addDomListener(target_, "mouseup", mouseUp_);

  setCursor_(false);
  if (opt_drag_.container) {

  }
  src.style.position = "absolute";
  opt_drag_.left = opt_drag_.left||src.offsetLeft;
  opt_drag_.top = opt_drag_.top||src.offsetTop;
  opt_drag_.interval = opt_drag_.interval||1;
  moveTo_(opt_drag_.left, opt_drag_.top, false);

  /**
   * Set the cursor for {@link src} based on whether or not
   *     the element is currently being dragged.
   * @param {Boolean} a Is the element being dragged?
   * @private
   */
  function setCursor_(a) {
    if(a) {
      src.style.cursor = draggingCursor_;
    } else {
      src.style.cursor = draggableCursor_;
    }
  }

  /**
   * Moves the element {@link src} to the given
   *     location.
   * @param {Number} x The left position to move to.
   * @param {Number} y The top position to move to.
   * @param {Boolean} prevent Prevent moving?
   * @private
   */
  function moveTo_(x, y, prevent) {
    var roundedIntervalX_, roundedIntervalY_;
    left_ = Math.round(x);
    top_ = Math.round(y);
    if (opt_drag_.intervalX>1) {
      roundedIntervalX_ = Math.round(left_%opt_drag_.intervalX);
      left_ = (roundedIntervalX_<halfIntervalX_)?(left_-roundedIntervalX_):(left_+(opt_drag_.intervalX-roundedIntervalX_));
    }
    if (opt_drag_.intervalY>1) {
      roundedIntervalY_ = Math.round(top_%opt_drag_.intervalY);
      top_ = (roundedIntervalY_<halfIntervalY_)?(top_-roundedIntervalY_):(top_+(opt_drag_.intervalY-roundedIntervalY_));
    }
    if (opt_drag_.container&&opt_drag_.container.offsetWidth) {
      left_ = Math.max(0,Math.min(left_,opt_drag_.container.offsetWidth-src.offsetWidth));
      top_ = Math.max(0,Math.min(top_,opt_drag_.container.offsetHeight-src.offsetHeight));
    }
    if (typeof currentX_ === "number") {
      if (((left_-currentX_)>opt_drag_.toleranceX||(currentX_-(left_+src.offsetWidth))>opt_drag_.toleranceX)||((top_-currentY_)>opt_drag_.toleranceY||(currentY_-(top_+src.offsetHeight))>opt_drag_.toleranceY)) {
        left_ = originalX_;
        top_ = originalY_;
      }
    }
    if(!opt_drag_.restrictX&&!prevent) {
      src.style.left = left_ + "px";
    }
    if(!opt_drag_.restrictY&&!prevent) {
      src.style.top = top_ + "px";
    }
  }

  /**
   * Handles the mousemove event.
   * @param {event} ev The event data sent by the browser.
   * @private
   */
  function mouseMove_(ev) {
    var e=ev||event;
    currentX_ = formerX_+((e.pageX||(e.clientX+document.body.scrollLeft+document.documentElement.scrollLeft))-formerMouseX_);
    currentY_ = formerY_+((e.pageY||(e.clientY+document.body.scrollTop+document.documentElement.scrollTop))-formerMouseY_);
    formerX_ = currentX_;
    formerY_ = currentY_;
    formerMouseX_ = e.pageX||(e.clientX+document.body.scrollLeft+document.documentElement.scrollLeft);
    formerMouseY_ = e.pageY||(e.clientY+document.body.scrollTop+document.documentElement.scrollTop);
    if (moving_) {
      moveTo_(currentX_,currentY_, preventDefault_);
      event_.trigger(me, "drag", {mouseX: formerMouseX_, mouseY: formerMouseY_, startLeft: originalX_, startTop: originalY_, event:e});
    }
  }

  /**
   * Handles the mousedown event.
   * @param {event} ev The event data sent by the browser.
   * @private
   */
  function mouseDown_(ev) {
    var e=ev||event;
    setCursor_(true);
    event_.trigger(me, "mousedown", e);
    if (src.style.position !== "absolute") {
      src.style.position = "absolute";
      return;
    }
    formerMouseX_ = e.pageX||(e.clientX+document.body.scrollLeft+document.documentElement.scrollLeft);
    formerMouseY_ = e.pageY||(e.clientY+document.body.scrollTop+document.documentElement.scrollTop);
    originalX_ = src.offsetLeft;
    originalY_ = src.offsetTop;
    formerX_ = originalX_;
    formerY_ = originalY_;
    mouseMoveEvent_ = event_.addDomListener(target_, "mousemove", mouseMove_);
    if (src.setCapture) {
      src.setCapture();
    }
    if (e.preventDefault) {
      e.preventDefault();
      e.stopPropagation();
    } else {
      e.cancelBubble=true;
      e.returnValue=false;
    }
    moving_ = true;
    event_.trigger(me, "dragstart", {mouseX: formerMouseX_, mouseY: formerMouseY_, startLeft: originalX_, startTop: originalY_, event:e});
  }

  /**
   * Handles the mouseup event.
   * @param {event} ev The event data sent by the browser.
   * @private
   */
  function mouseUp_(ev) {
    var e=ev||event;
    if (moving_) {
      setCursor_(false);
      event_.removeListener(mouseMoveEvent_);
      if (src.releaseCapture) {
        src.releaseCapture();
      }
      moving_ = false;
      event_.trigger(me, "dragend", {mouseX: formerMouseX_, mouseY: formerMouseY_, startLeft: originalX_, startTop: originalY_, event:e});
    }
    currentX_ = currentY_ = null;
    event_.trigger(me, "mouseup", e);
  }

  /**
   * Move the element {@link src} to the given location.
   * @param {Point} point An object with an x and y property
   *     that represents the location to move to.
   */
  me.moveTo = function(point) {
    moveTo_(point.x, point.y, false);
  };

  /**
   * Move the element {@link src} by the given amount.
   * @param {Size} size An object with an x and y property
   *     that represents distance to move the element.
   */
  me.moveBy = function(size) {
    moveTo_(src.offsetLeft + size.width, src.offsetHeight + size.height, false);
  }

  /**
   * Sets the cursor for the dragging state.
   * @param {String} cursor The name of the cursor to use.
   */
  me.setDraggingCursor = function(cursor) {
    draggingCursor_ = cursor;
    setCursor_(moving_);
  };

  /**
   * Sets the cursor for the draggable state.
   * @param {String} cursor The name of the cursor to use.
   */
  me.setDraggableCursor = function(cursor) {
    draggableCursor_ = cursor;
    setCursor_(moving_);
  };

  /**
   * Returns the current left location.
   * @return {Number}
   */
  me.left = function() {
    return left_;
  };

  /**
   * Returns the current top location.
   * @return {Number}
   */
  me.top = function() {
    return top_;
  };

  /**
   * Returns the number of intervals the element has moved
   *     along the X axis. Useful for scrollbar type
   *     applications.
   * @return {Number}
   */
  me.valueX = function() {
    var i = opt_drag_.intervalX||1;
    return Math.round(left_ / i);
  };

  /**
   * Returns the number of intervals the element has moved
   *     along the Y axis. Useful for scrollbar type
   *     applications.
   * @return {Number}
   */
  me.valueY = function() {
    var i = opt_drag_.intervalY||1;
    return Math.round(top_ / i);
  };

  /**
   * Sets the left position of the draggable object based on
   *     intervalX.
   * @param {Number} value The location to move to.
   */
  me.setValueX = function(value) {
    moveTo_(value * opt_drag_.intervalX, top_, false);
  };

  /**
   * Sets the top position of the draggable object based on
   *     intervalY.
   * @param {Number} value The location to move to.
   */
  me.setValueY = function(value) {
    moveTo_(left_, value * opt_drag_.intervalY, false);
  };

  /**
   * Prevents the default movement behavior of the object.
   *     The object can still be moved by other methods.
   */
  me.preventDefaultMovement = function(prevent) {
    preventDefault_ = prevent;
  };
}
  /**
   * @name ExtDraggableObjectOptions
   * @class This class represents the optional parameter passed into constructor of
   * <code>ExtDraggableObject</code>.
   * @property {Number} [top] Top pixel
   * @property {Number} [left] Left pixel
   * @property {HTMLElement} [container] HTMLElement as container.
   * @property {String} [draggingCursor] Dragging Cursor
   * @property {String} [draggableCursor] Draggable Cursor
   * @property {Number} [intervalX] Interval in X direction
   * @property {Number} [intervalY] Interval in Y direction
   * @property {Number} [toleranceX] Tolerance X in pixel
   * @property {Number} [toleranceY] Tolerance Y in pixel
   * @property {Boolean} [restrictX] Whether to restrict move in X direction
   * @property {Boolean} [restrictY] Whether to restrict move in Y direction
   */

 // End of https://github.com/gavinharriss/google-maps-v3-opacity-control/blob/master/ExtDraggableObject.js
ext_draggable_object_jsav*  <!DOCTYPE html>
            <html>
              <head>
                <title>%(xml_escaped_title)s</title>
                <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
                <meta http-equiv='imagetoolbar' content='no'/>
                <style type="text/css"> v\:* {behavior:url(#default#VML);}
                    html, body { overflow: hidden; padding: 0; height: 100%%; width: 100%%; font-family: 'Lucida Grande',Geneva,Arial,Verdana,sans-serif; }
                    body { margin: 10px; background: #fff; }
                    h1 { margin: 0; padding: 6px; border:0; font-size: 20pt; }
                    #header { height: 43px; padding: 0; background-color: #eee; border: 1px solid #888; }
                    #subheader { height: 12px; text-align: right; font-size: 10px; color: #555;}
                    #map { height: 95%%; border: 1px solid #888; }
                 </style>
          %(googlemapsurl_hint)s
          <script src='%(googlemapsurl)s'></script>
          <script>
          //<![CDATA[

                /*
                 * Constants for given map
                 * TODO: read it from tilemapresource.xml
                 */

                var mapBounds = new google.maps.LatLngBounds(
                    new google.maps.LatLng(%(south)s, %(west)s),
                    new google.maps.LatLng(%(north)s, %(east)s));
                var mapMinZoom = %(minzoom)s;
                var mapMaxZoom = %(maxzoom)s;


                var initialOpacity = 0.75 * 100;
                var map;

                /*
                 * Full-screen Window Resize
                 */

                function getWindowHeight() {
                    if (self.innerHeight) return self.innerHeight;
                    if (document.documentElement && document.documentElement.clientHeight)
                        return document.documentElement.clientHeight;
                    if (document.body) return document.body.clientHeight;
                    return 0;
                }

                function getWindowWidth() {
                    if (self.innerWidth) return self.innerWidth;
                    if (document.documentElement && document.documentElement.clientWidth)
                        return document.documentElement.clientWidth;
                    if (document.body) return document.body.clientWidth;
                    return 0;
                }

                function resize() {
                    var map = document.getElementById("map");
                    var header = document.getElementById("header");
                    var subheader = document.getElementById("subheader");
                    map.style.height = (getWindowHeight()-80) + "px";
                    map.style.width = (getWindowWidth()-20) + "px";
                    header.style.width = (getWindowWidth()-20) + "px";
                    subheader.style.width = (getWindowWidth()-20) + "px";
                    // map.checkResize();
                }


                // getZoomByBounds(): adapted from https://stackoverflow.com/a/9982152
                /**
                * Returns the zoom level at which the given rectangular region fits in the map view.
                * The zoom level is computed for the currently selected map type.
                * @param {google.maps.Map} map
                * @param {google.maps.LatLngBounds} bounds
                * @return {Number} zoom level
                **/
                function getZoomByBounds(  map, bounds ){
                  var MAX_ZOOM = 21 ;
                  var MIN_ZOOM =  0 ;

                  var ne= map.getProjection().fromLatLngToPoint( bounds.getNorthEast() );
                  var sw= map.getProjection().fromLatLngToPoint( bounds.getSouthWest() );

                  var worldCoordWidth = Math.abs(ne.x-sw.x);
                  var worldCoordHeight = Math.abs(ne.y-sw.y);
                  //Fit padding in pixels
                  var FIT_PAD = 40;
                  for( var zoom = MAX_ZOOM; zoom >= MIN_ZOOM; --zoom ){
                      if( worldCoordWidth*(1<<zoom)+2*FIT_PAD < map.getDiv().offsetWidth &&
                          worldCoordHeight*(1<<zoom)+2*FIT_PAD < map.getDiv().offsetHeight )
                      {
                          if( zoom > mapMaxZoom )
                              zoom = mapMaxZoom;
                          return zoom;
                      }
                  }
                  return 0;
                }

                function fromMercatorPixelToLatLng(pixel, zoom)
                {
                    var CST = 6378137 * Math.PI;
                    var res = 2 * CST / 256 / Math.pow(2, zoom);
                    var X = -CST + pixel.x * res;
                    var Y = CST - pixel.y * res;
                    var lon = X / CST * 180;
                    var lat = Math.atan(Math.sinh(Y / CST * Math.PI)) / Math.PI * 180;
                    return new google.maps.LatLng(lat, lon);
                }


                var OPACITY_MAX_PIXELS = 57; // Width of opacity control image

                function createOpacityControl(map, opacity) {
                    var sliderImageUrl = "https://gdal.org/resources/gdal2tiles/opacity-slider.png";

                    // Create main div to hold the control.
                    var opacityDiv = document.createElement('DIV');
                    var opacityDivMargin = 5;
                    opacityDiv.setAttribute("style", "margin:" + opacityDivMargin + "px;overflow-x:hidden;overflow-y:hidden;background:url(" + sliderImageUrl + ") no-repeat;width:71px;height:21px;cursor:pointer;");

                    // Create knob
                    var opacityKnobDiv = document.createElement('DIV');
                    opacityKnobDiv.setAttribute("style", "padding:0;margin:0;overflow-x:hidden;overflow-y:hidden;background:url(" + sliderImageUrl + ") no-repeat -71px 0;width:14px;height:21px;");
                    opacityDiv.appendChild(opacityKnobDiv);

                    var opacityCtrlKnob = new ExtDraggableObject(opacityKnobDiv, {
                        restrictY: true,
                        container: opacityDiv
                    });

                    google.maps.event.addListener(opacityCtrlKnob, "dragend", function () {
                        setOpacity(opacityCtrlKnob.valueX());
                    });

                    google.maps.event.addDomListener(opacityDiv, "click", function (e) {
                        var left = this.getBoundingClientRect().left;
                        var x = e.pageX - left - opacityDivMargin;
                        opacityCtrlKnob.setValueX(x);
                        setOpacity(x);
                    });

                    map.controls[google.maps.ControlPosition.TOP_RIGHT].push(opacityDiv);

                    // Set initial value
                    var initialValue = OPACITY_MAX_PIXELS / (100 / opacity);
                    opacityCtrlKnob.setValueX(initialValue);
                    setOpacity(initialValue);
                }

                function setOpacity(pixelX) {
                    // Range = 0 to OPACITY_MAX_PIXELS
                    var value = (100 / OPACITY_MAX_PIXELS) * pixelX;
                    if (value < 0) value = 0;
                    if (value == 0) {
                        if (overlay.visible == true) {
                            overlay.hide();
                        }
                    }
                    else {
                        overlay.setOpacity(value);
                        if (overlay.visible == false) {
                            overlay.show();
                        }
                    }
                }

                function createCopyrightControl(map, copyright) {
                    const label = document.createElement("label");
                    label.style.backgroundColor = "#ffffff";
                    label.textContent = copyright;

                    const div = document.createElement("div");
                    div.appendChild(label);

                    map.controls[google.maps.ControlPosition.BOTTOM_RIGHT].push(div);
                }

                %(ext_draggable_object_js)s

                /*
                 * Main load function:
                 */

                function load() {

                    var options = {
                      center: mapBounds.getCenter(),
                      zoom: mapMaxZoom,
                      mapTypeId: google.maps.MapTypeId.HYBRID,

                      // Add map type control
                      mapTypeControl: true,
                      mapTypeControlOptions: {
                          style: google.maps.MapTypeControlStyle.HORIZONTAL_BAR,
                          position: google.maps.ControlPosition.TOP_LEFT
                      },

                      // Add scale
                      scaleControl: true,
                      scaleControlOptions: {
                          position: google.maps.ControlPosition.BOTTOM_RIGHT
                      }
                    };

                    map = new google.maps.Map( document.getElementById("map"), options);
                    google.maps.event.addListenerOnce(map, "projection_changed", function() {
                       map.setZoom(getZoomByBounds( map, mapBounds ));
                    });

                    %(custom_tile_overlay_js)s

                    overlay = new CustomTileOverlay(map, initialOpacity);
                    overlay.show();

                    google.maps.event.addListener(map, 'tilesloaded', function () {
                        overlay.deleteHiddenTiles(map.getZoom());
                    });

                    // Add opacity control and set initial value
                    createOpacityControl(map, initialOpacity);

                    var copyright = "%(copyright)s";
                    if( copyright != "" ) {
                        createCopyrightControl(map, copyright);
                    }

                    resize();
                }

                onresize=function(){ resize(); };

                //]]>
                </script>
              </head>
              <body onload="load()">
                  <div id="header"><h1>%(xml_escaped_title)s</h1></div>
                  <div id="subheader">Generated by <a href="https://gdal.org/programs/gdal2tiles.html">GDAL2Tiles</a>, Copyright &copy; 2008 <a href="http://www.klokan.cz/">Klokan Petr Pridal</a>,  <a href="https://gdal.org">GDAL</a> &amp; <a href="http://www.osgeo.org/">OSGeo</a> <a href="http://code.google.com/soc/">GSoC</a>
            <!-- PLEASE, LET THIS NOTE ABOUT AUTHOR AND PROJECT SOMEWHERE ON YOUR WEBSITE, OR AT LEAST IN THE COMMENT IN HTML. THANK YOU -->
                  </div>
                   <div id="map"></div>
              </body>
            </html>
        )r   r+  r3  r,  r-  r  r9  rf  re  rZ   r1  r0  r  r:   r5  r7  s      r,   r  zGDAL2Tiles.generate_googlemaps  s[    $($5$5LL%
 ! !J_<<!!%;;!Wt||/E/E%EE!)+D%& s $ DH99@WtF|T']DL**Y**Y NN[!\\\!\\--\ LL22[v 	$	
x 	%	
H
qd er 	
t r-   c                    i }| j                   j                  j                  dd      |d<   t        j                  | j                   j                  t        j
                        |d<   | j                  \  |d<   |d<   |d<   |d<   |d   |d   z   d	z  |d
<   |d   |d   z   d	z  |d<   | j                  |d<   | j                  |d<   | j                  |d<   | j                  |d<   | j                  |d<   | j                   j                  |d<   | j                   j                  j                  dd      |d<   | j                   j                  rd|d<   nd|d<   d|z  }|S )z
        Template for leaflet.html implementing overlay of tiles for 'mercator' profile.
        It returns filled string. Expected variables:
        title, north, south, east, west, minzoom, maxzoom, tile_size, tileformat, publishurl
        "z\"double_quote_escaped_titler#  r&  r'  r(  r)  r   	centerlon	centerlatr  r  	beginzoomrZ   r   r  r  r   r   r=   aN  <!DOCTYPE html>
        <html lang="en">
          <head>
            <meta charset="utf-8">
            <meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no' />
            <title>%(xml_escaped_title)s</title>

            <!-- Leaflet -->
            <link rel="stylesheet" href="https://unpkg.com/leaflet@0.7.5/dist/leaflet.css" />
            <script src="https://unpkg.com/leaflet@0.7.5/dist/leaflet.js"></script>

            <style>
                body { margin:0; padding:0; }
                body, table, tr, td, th, div, h1, h2, input { font-family: "Calibri", "Trebuchet MS", "Ubuntu", Serif; font-size: 11pt; }
                #map { position:absolute; top:0; bottom:0; width:100%%; } /* full size */
                .ctl {
                    padding: 2px 10px 2px 10px;
                    background: white;
                    background: rgba(255,255,255,0.9);
                    box-shadow: 0 0 15px rgba(0,0,0,0.2);
                    border-radius: 5px;
                    text-align: right;
                }
                .title {
                    font-size: 18pt;
                    font-weight: bold;
                }
                .src {
                    font-size: 10pt;
                }

            </style>

        </head>
        <body>

        <div id="map"></div>

        <script>
        /* **** Leaflet **** */

        // Base layers
        //  .. OpenStreetMap
        var osm = L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors', minZoom: %(minzoom)s, maxZoom: %(maxzoom)s});

        //  .. CartoDB Positron
        var cartodb = L.tileLayer('http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png', {attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, &copy; <a href="http://cartodb.com/attributions">CartoDB</a>', minZoom: %(minzoom)s, maxZoom: %(maxzoom)s});

        //  .. OSM Toner
        var toner = L.tileLayer('http://{s}.tile.stamen.com/toner/{z}/{x}/{y}.png', {attribution: 'Map tiles by <a href="http://stamen.com">Stamen Design</a>, under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>. Data by <a href="http://openstreetmap.org">OpenStreetMap</a>, under <a href="http://www.openstreetmap.org/copyright">ODbL</a>.', minZoom: %(minzoom)s, maxZoom: %(maxzoom)s});

        //  .. White background
        var white = L.tileLayer("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEAAQMAAABmvDolAAAAA1BMVEX///+nxBvIAAAAH0lEQVQYGe3BAQ0AAADCIPunfg43YAAAAAAAAAAA5wIhAAAB9aK9BAAAAABJRU5ErkJggg==", {minZoom: %(minzoom)s, maxZoom: %(maxzoom)s});

        // Overlay layers (TMS)
        var lyr = L.tileLayer('./{z}/{x}/{y}.%(tileformat)s', {tms: %(tms)s, opacity: 0.7, attribution: "%(copyright)s", minZoom: %(minzoom)s, maxZoom: %(maxzoom)s});

        // Map
        var map = L.map('map', {
            center: [%(centerlon)s, %(centerlat)s],
            zoom: %(beginzoom)s,
            minZoom: %(minzoom)s,
            maxZoom: %(maxzoom)s,
            layers: [osm]
        });

        var basemaps = {"OpenStreetMap": osm, "CartoDB Positron": cartodb, "Stamen Toner": toner, "Without background": white}
        var overlaymaps = {"Layer": lyr}

        // Title
        var title = L.control();
        title.onAdd = function(map) {
            this._div = L.DomUtil.create('div', 'ctl title');
            this.update();
            return this._div;
        };
        title.update = function(props) {
            this._div.innerHTML = "%(double_quote_escaped_title)s";
        };
        title.addTo(map);

        // Note
        var src = 'Generated by <a href="https://gdal.org/programs/gdal2tiles.html">GDAL2Tiles</a>, Copyright &copy; 2008 <a href="http://www.klokan.cz/">Klokan Petr Pridal</a>,  <a href="https://gdal.org">GDAL</a> &amp; <a href="http://www.osgeo.org/">OSGeo</a> <a href="http://code.google.com/soc/">GSoC</a>';
        var title = L.control({position: 'bottomleft'});
        title.onAdd = function(map) {
            this._div = L.DomUtil.create('div', 'ctl src');
            this.update();
            return this._div;
        };
        title.update = function(props) {
            this._div.innerHTML = src;
        };
        title.addTo(map);


        // Add base layers
        L.control.layers(basemaps, overlaymaps, {collapsed: false}).addTo(map);

        // Fit to overlay bounds (SW and NE points with (lat, lon))
        map.fitBounds([[%(south)s, %(east)s], [%(north)s, %(west)s]]);

        </script>

        </body>
        </html>

        )r3  r,  replacer   r+  r-  r9  rf  re  rZ   r1  r0  r  rA  r  s      r,   r  zGDAL2Tiles.generate_leaflet  sj    -1\\-?-?-G-GU-S)*$($5$5LL%
 ! DH99@WtF|T']DL!']T']:cA[!&\DL8C?[**Y**Y JJ[ NN[!\\\!\\--\ LL22::3F[<<DKDKjV Wk 	
^ r-   c           	         i }t        j                  | j                  j                  t         j                        |d<   | j                  j
                  |d<   | j                  |d<   | j                  |d<   | j                  |d<   | j                  |d<   | j                  j                  |d<   | j                  j                  |d<   | j                  j                  rd	|d
<   nd|d
<   | j                  |d<   | j                  |d<   | j                  |d<   | j                   |d<   | j                  | j                  z   dz  |d<   | j                  | j                   z   dz  |d<   d|z  }| j                  j"                  dk(  s| j                  j"                  dk(  r|d|z  z  }| j                  j"                  dk(  r
|d|z  z  }n| j                  j"                  dk(  r| j                  j$                  rd| j                  z  }nd| j                  z  }t'        | j                  dz         D cg c]
  }|d|z  z   }}ddj)                  d |D              z   dz   |d<   | j                  j                  r'| j                  j$                  rd |d!<   nd"|d!<   d#|d$<   n
d%|d!<   d&|d$<   |d'|z  z  }n| j                  j"                  d(k(  rd| j*                  z  | j,                  d   z  }t'        | j                  dz         D cg c]
  }|d|z  z   }}|| j                     |d)<   ddj)                  d* |D              z   dz   |d<   d+| j                  | j                  | j                  | j                   fz  |d,<   | j                  j                  r$d-| j                  | j                   fz  |d!<   d#|d$<   n#d-| j                  | j                  fz  |d!<   d&|d$<   |d.|z  z  }nt.        | j                  j"                     j0                  }t'        | j                  dz         D cg c]
  }|d|z  z   }}|| j                     |d)<   ddj)                  d/ |D              z   dz   |d<   ddj)                  fd0t'        t3        |            D              z   dz   |d1<   | j                  j                  r$d-j4                  j6                  fz  |d!<   d#|d$<   n=d-j4                  j6                  j0                  j                  z  z
  fz  |d!<   d&|d$<   d+j4                  j6                  j8                  j0                  z  j                  z  z
  j4                  j:                  j0                  z  j                  z  z   j6                  fz  |d,<   |d2|z  z  }|d3|z  z  }| j                  j"                  d4v rM|d   |d5<   | j                  j"                  dk(  r#| j                  j$                  r|d5xx   dz  cc<   |d6|z  z  }n|d7|z  z  }| j                  j"                  dk(  r|d8z  }n~| j                  j"                  dk7  re| j<                  rY| j<                  j?                         r?| j<                  jA                  d9      d:k(  r!|d;| j<                  jC                  d9      z  z  }|d<z  }| j                  j"                  d4v r|d=z  }|d>z  }|S c c}w c c}w c c}w )?z
        Template for openlayers.html, with the tiles as overlays, and base layers.

        It returns filled string.
        r#  r  r  r  rZ   r   r  r  r   sign_yr  r  r  r  r  r`   center_xcenter_yac  <!DOCTYPE html>
<html>
    <head>
    <title>%(xml_escaped_title)s</title>
    <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
    <meta http-equiv='imagetoolbar' content='no'/>
    <style type="text/css"> v\:* {behavior:url(#default#VML);}
        html, body { overflow: hidden; padding: 0; height: 100%%; width: 100%%; font-family: 'Lucida Grande',Geneva,Arial,Verdana,sans-serif; }
        body { margin: 10px; background: #fff; }
        h1 { margin: 0; padding: 6px; border:0; font-size: 20pt; }
        #header { height: 43px; padding: 0; background-color: #eee; border: 1px solid #888; }
        #subheader { height: 12px; text-align: right; font-size: 10px; color: #555;}
        #map { height: 90%%; border: 1px solid #888; }
    </style>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@main/dist/en/v7.0.0/legacy/ol.css" type="text/css">
    <script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@main/dist/en/v7.0.0/legacy/ol.js"></script>
    <script src="https://unpkg.com/ol-layerswitcher@4.1.1"></script>
    <link rel="stylesheet" href="https://unpkg.com/ol-layerswitcher@4.1.1/src/ol-layerswitcher.css" />
</head>
<body>
    <div id="header"><h1>%(xml_escaped_title)s</h1></div>
    <div id="subheader">Generated by <a href="https://gdal.org/programs/gdal2tiles.html">GDAL2Tiles</a>&nbsp;&nbsp;&nbsp;&nbsp;</div>
    <div id="map" class="map"></div>
    <div id="mouse-position"></div>
    <script type="text/javascript">
        var mousePositionControl = new ol.control.MousePosition({
            className: 'custom-mouse-position',
            target: document.getElementById('mouse-position'),
            undefinedHTML: '&nbsp;'
        });
        var map = new ol.Map({
            controls: ol.control.defaults.defaults().extend([mousePositionControl]),
            target: 'map',
r   r   a
  
            layers: [
                new ol.layer.Group({
                        title: 'Base maps',
                        layers: [
                            new ol.layer.Tile({
                                title: 'OpenStreetMap',
                                type: 'base',
                                visible: true,
                                source: new ol.source.OSM()
                            }),
                            new ol.layer.Tile({
                                title: 'Bing Roads',
                                type: 'base',
                                visible: false,
                                source: new ol.source.BingMaps({
                                    key: "%(bingkey)s",
                                    imagerySet: 'Road'
                                })
                            }),
                            new ol.layer.Tile({
                                title: 'Bing Aerial',
                                type: 'base',
                                visible: false,
                                source: new ol.source.BingMaps({
                                    key: "%(bingkey)s",
                                    imagerySet: 'Aerial'
                                })
                            }),
                            new ol.layer.Tile({
                                title: 'Bing Hybrid',
                                type: 'base',
                                visible: false,
                                source: new ol.source.BingMaps({
                                    key: "%(bingkey)s",
                                    imagerySet: 'AerialWithLabels'
                                })
                            }),
                        ]
                }),a!  
                new ol.layer.Group({
                    title: 'Overlay',
                    layers: [
                        new ol.layer.Tile({
                            title: 'Overlay',
                            // opacity: 0.7,
                            extent: [%(ominx)f, %(ominy)f,%(omaxx)f, %(omaxy)f],
                            source: new ol.source.XYZ({
                                attributions: '%(copyright)s',
                                minZoom: %(minzoom)d,
                                maxZoom: %(maxzoom)d,
                                url: './{z}/{x}/{%(sign_y)sy}.%(tileformat)s',
                                tileSize: [%(tile_size)d, %(tile_size)d]
                            })
                        }),
                    ]
                }),r   r   r=   [rv  c              3   &   K   | ]	  }d |z    ywz%.18gNrF   .0rf   s     r,   	<genexpr>z1GDAL2Tiles.generate_openlayers.<locals>.<genexpr>       Dw}D   ]resolutionsz	[-180,90]originz
[-180,270]ztileCoord[2]	y_formulaz
[-180,-90]z- 1 - tileCoord[2]a  
                new ol.layer.Group({
                    title: 'Overlay',
                    layers: [
                        new ol.layer.Tile({
                            title: 'Overlay',
                            // opacity: 0.7,
                            extent: [%(ominx)f, %(ominy)f,%(omaxx)f, %(omaxy)f],
                            source: new ol.source.TileImage({
                                attributions: '%(copyright)s',
                                projection: 'EPSG:4326',
                                minZoom: %(minzoom)d,
                                maxZoom: %(maxzoom)d,
                                tileGrid: new ol.tilegrid.TileGrid({
                                    extent: [-180,-90,180,90],
                                    origin: %(origin)s,
                                    resolutions: %(resolutions)s,
                                    tileSize: [%(tile_size)d, %(tile_size)d]
                                }),
                                tileUrlFunction: function(tileCoord) {
                                    return ('./{z}/{x}/{y}.%(tileformat)s'
                                        .replace('{z}', String(tileCoord[0]))
                                        .replace('{x}', String(tileCoord[1]))
                                        .replace('{y}', String(%(y_formula)s)));
                                },
                            })
                        }),
                    ]
                }),r   maxresc              3   &   K   | ]	  }d |z    ywr,  rF   r-  s     r,   r/  z1GDAL2Tiles.generate_openlayers.<locals>.<genexpr>  r0  r1  z[%.18g,%.18g,%.18g,%.18g]tilegrid_extentz[%.18g,%.18g]a  
            layers: [
                new ol.layer.Group({
                    title: 'Overlay',
                    layers: [
                        new ol.layer.Tile({
                            title: 'Overlay',
                            // opacity: 0.7,
                            source: new ol.source.TileImage({
                                attributions: '%(copyright)s',
                                tileGrid: new ol.tilegrid.TileGrid({
                                    extent: %(tilegrid_extent)s,
                                    origin: %(origin)s,
                                    resolutions: %(resolutions)s,
                                    tileSize: [%(tile_size)d, %(tile_size)d]
                                }),
                                tileUrlFunction: function(tileCoord) {
                                    return ('./{z}/{x}/{y}.%(tileformat)s'
                                        .replace('{z}', String(tileCoord[0]))
                                        .replace('{x}', String(tileCoord[1]))
                                        .replace('{y}', String(%(y_formula)s)));
                                },
                            })
                        }),
                    ]
                }),c              3   &   K   | ]	  }d |z    ywr,  rF   r-  s     r,   r/  z1GDAL2Tiles.generate_openlayers.<locals>.<genexpr>$  r0  r1  c              3   `   K   | ]%  }d j                   |z  j                  |z  fz   ' yw)z[%d,%d]N)rX   rY   )r.  rn   r   s     r,   r/  z1GDAL2Tiles.generate_openlayers.<locals>.<genexpr>(  s9       !1!1Q!68I8IQ8N OOs   +.matrixsizesa  
            layers: [
                new ol.layer.Group({
                    title: 'Overlay',
                    layers: [
                        new ol.layer.Tile({
                            title: 'Overlay',
                            // opacity: 0.7,
                            extent: [%(ominx)f, %(ominy)f,%(omaxx)f, %(omaxy)f],
                            source: new ol.source.TileImage({
                                attributions: '%(copyright)s',
                                minZoom: %(minzoom)d,
                                maxZoom: %(maxzoom)d,
                                tileGrid: new ol.tilegrid.TileGrid({
                                    extent: %(tilegrid_extent)s,
                                    origin: %(origin)s,
                                    resolutions: %(resolutions)s,
                                    sizes: %(matrixsizes)s,
                                    tileSize: [%(tile_size)d, %(tile_size)d]
                                }),
                                tileUrlFunction: function(tileCoord) {
                                    return ('./{z}/{x}/{y}.%(tileformat)s'
                                        .replace('{z}', String(tileCoord[0]))
                                        .replace('{x}', String(tileCoord[1]))
                                        .replace('{y}', String(%(y_formula)s)));
                                },
                            })
                        }),
                    ]
                }),ze
            ],
            view: new ol.View({
                center: [%(center_x)f, %(center_y)f],r   r   	view_zoomz%
                zoom: %(view_zoom)d,z(
                resolution: %(maxres)f,z)
                projection: 'EPSG:4326',Nr  zR
                projection: new ol.proj.Projection({code: 'EPSG:%s', units:'m'}),z
            })
        });z8
        map.addControl(new ol.control.LayerSwitcher());z
    </script>
</body>
</html>)"r   r+  r3  r,  r-  r  rf  re  rZ   r1  r0  r  rA  r  r  r  r  r  r   rl   r
  r  r  r  r[   r?   rV   rW   rY   rX   r  r   r  r  )r:   r5  r7  base_resrn   r3  r   s         @r,   r  zGDAL2Tiles.generate_openlayers+  s$    $($5$5LL%
 ! ,,..Y**Y**Y NN[!\\\!\\--\ LL22[<<DN DN

W

W

W

W JJ3q8Z JJ3q8Z!D E" 	
L <<:-1E1E1S'P Q(*AX <<:-$ %A, \\!!Z/||)) 4>>1 4>>149$**q.4IJq8ad?JKJchhDDDDsJ  ||<<--%0DN%1DN$2[!!-X$8[!: ;AB \\!!X-T__-A>H49$**q.4IJq8ad?JKJ(4DNchhDDDDsJ  'B







	E 'D"# ||!0DJJ

3K!KX$2[!!0DJJ

3K!KX$8[!4 5A@ --.C~~H49$**q.4IJq8ad?JKJ(4DNchhDDDDsJ  (( "3{#34 
   ||!0CMM3==3Q!QX$2[!!0MMMMCNNS]]$BB4 "X %9[!&A 1 1CNN BS]] RR 0 03>> ACMM QQ	E 'D"# < = AD 	
9 		
 <<#;; $YD||##z1dll6P6P[!Q&!(A +A <<:- , ,A\\!!Z/KK++-KK006&@ UW[WbWbWsWsX 
 	
  	 <<#;; ; ;A	  	
 u Kf Kj Ks   +[[#["c           
         | j                   j                  r| j                   j                  }nt        j                  dd      }t	        |d      j                         j                  d      }| j                   j                  dk(  rd}n2| j                   j                  dk(  rd}n| j                   j                  }|j                  d	|      }|j                  d
| j                   j                  r| j                   j                  nd      }| j                  | j                     \  }}}}|j                  dt        |            }|j                  dt        t        j                  || j                  | j                                     }|j                  dt        |            }|j                  dt        t        j                  || j                  | j                                     }|j                  dt        | j                              }|j                  dt        | j                              }|j                  dt        | j                              }|j                  dt        | j                               }|S )Nr   ztemplate_tiles.mapmlr   r   r   OSMTILEr   WGS84z${TILING_SCHEME}z${URL}z./z${MINTILEX}z${MINTILEY}z${MAXTILEX}z${MAXTILEY}z
${CURZOOM}z
${MINZOOM}z
${MAXZOOM}z
${TILEEXT})r3  r  r   FindFilerJ   readr  r  r%  r0  rZ  re  r   r.  r/  rf  r1  )r:   templater7  tiling_schemer]  r^  r_  r`  s           r,   r  zGDAL2Tiles.generate_mapml  s   <<&&||22H}}V-CDH4 %%'..w7<<:-%M\\!!Z/#M LL00MII(-8IIhDLL4D4D 0 0$O%)\\$**%="ueUIImSZ0II3z225$**dllST
 IImSZ0II3z225$**dllST
 IIlC

O4IIlC

O4IIlC

O4IIlC$56r-   c                     |j                   rS|j                  dk7  rD|j                  dv rd|z  dz
  | z
  S t        |j                     }|j                  d|z  z  dz
  | z
  S | S )z
        Calculates the y-tile number based on whether XYZ or TMS (default) system is used
        :param ty: The y-tile number
        :param tz: The z-tile number
        :return: The transformed y-tile number
        r   r<  r`   r=   )rA  r  r  rY   )rh   r  r3  r   s       r,   r/  zGDAL2Tiles.getYTile  so     ;;7??h6"::2	R'')C!!ArE)A-  	r-   r   )r   )rB   rC   rD   r   Optionsr;   r  r  r	   r	  r   r
  r  r  r  r  r  r  r  r   r/  rF   r-   r,   r.  r.    s    H$3 H$s H$W H$QU H$Vp>dzx_"U;Z8H+H%I _"B*BXA# AFUS UnK# KZhS hT B  r-   r.  c                     t        | ||      }|j                          |j                          |j                         \  }}||fS r7   )r.  r  r  r  )r  r>  r3  r"   r  r  s         r,   worker_tile_detailsrI    sH     Jw?J  "","@"@"BM<,&&r-   c                   N    e Zd Zej                  fdeddfdZddZd	deddfdZy)
ProgressBartotal_itemsrR   Nc                 .    || _         d| _        || _        y )Nr   )rL  nb_items_doneprogress_cbk)r:   rL  rO  s      r,   r;   zProgressBar.__init__  s    &(r-   c                 *    | j                  ddd        y )Nr   r   )rO  r]   s    r,   r  zProgressBar.start  s    !R&r-   nb_itemsc                     | xj                   |z  c_         t        | j                         | j                  z  }| j                  |dd        y )Nr   )rN  r   rL  rO  )r:   rQ  progresss      r,   log_progresszProgressBar.log_progress  s@    h&++,t/?/??(B-r-   r   )r=   )	rB   rC   rD   r   TermProgress_nocbra   r;   r  rT  rF   r-   r,   rK  rK    s7    6:6L6L )C )QU )
'.S . .r-   rK  c                     j                   dk(  rt               }|j                  }|S j                   dk(  r#t        j                        }|j                  }|S j                   dk(  rt        j                         }|j                  d       |j                  t
        j                          j                  r{ j                  rot        j                         }|j                  t
        j                         |j                   j                         t        j                  ||       fd}|}|S d }|S d }|S )Nr   r   r   r  c                    d
j                   |z
  z  
j                  d   z  }
j                  d   | 
j                  z  |z  z   }|
j                  |z  z   }	j                  r5
j                  d   |
j                  z  |z  z
  }|
j                  |z  z
  }n1
j                  |
j                  z  |z  z   }|
j                  |z  z   }
j
                  s0j                  ||      d d \  }}j                  ||      d d \  }}||||fS )Nr`   r=   r   r   )re  r  rZ   rA  r  r  r  )rb   rc   rd   r  r'  r)  r(  r&  r  r3  r  s           r,   r  z%get_tile_swne.<locals>.rastertileswne  sH   ---12]5P5PQR5SS  "//2-111J>?  m55
BB;;%33A6m555
BC  "M$;$;j$HHE &++a-2I2I.IJ.VV  "M$;$;j$HHE$11"$"3"3D%"@!"DKD%"$"3"3D%"@!"DKD%dE4//r-   c                      yr  rF   r  s      r,   r  zget_tile_swne.<locals>.<lambda>  r  r-   )r  r   r   r   r   r   r   r  r  r  r/  r  r  r  )	r  r3  r   	tile_swner   r  r  r  r  s	   ``      @r,   r0  r0    s&   *$!#--	\ [ 
J	&!'"7"78--	V U 
H	$&&(t$&&s'E'EF!9!9))+F))#*H*HI  !9!9:--fg>B04 'I 	 5I  	r-   c           	         |j                   rt        j                  d       t        | ||      \  }}|j                   rt        j                  d       |j                   s0|j                  s$t        t        |            }|j                          |D ]8  }t        ||       |j                   r|j                  r)j                          : t        t        dd      rt        `|j                  sIt        |      }|r<t        j                  d       |j                   st        |      }|j                          t        |j                   |j"                  d      D ]O  }	t%        |	||      }
|
D ];  }t'        |	||||       |j                   r|j                  r,j                          = Q t)        j*                  t,        j.                  j1                  |j2                               y)zy
    Keep a single threaded version that stays clear of multiprocessing, for platforms that would not
    support it
    Begin tiles details calcTiles details calc complete.r  NGenerating Overview Tiles:r   )r~  r  r  rI  ru  rK  r?   r  r;  rT  r  r  r  rh  r  rl   re  rf  rc  rX  shutilrmtreer)   r+   dirnamer  )r  r>  r3  r  r  base_progress_barr2  r,  overview_progress_barr<  base_tile_groupsr=  s               r,   single_threaded_tilingrd    ss    /0,ZPD,34??7=='L(9:!# -{+w}}**,	- {K.!==$T*KK45??(3E(:%%++-TZZ4 54WmTR* 	5J *mT7S??7==%224	55 MM"''//$--01r-   c           
         |j                   xs d}|j                  rt        j                  d       t	        | ||      \  }}|j                  rt        j                  d       |j                  s0|j
                  s$t        t        |            }|j                          t        dt        dt        |      |z              }|j                  t        t        |      ||      D ],  }	|j                  r|j
                  rj                          . |j
                  sIt        |      }
|
r<t        j!                  d       |j                  st        |
      }|j                          t#        |j$                  |j&                  d      D ]  }t)        |||      }t        dt        dt        |      |z              }|j                  t        t*        ||||      ||      D ],  }	|j                  r|j
                  rj                          .  t-        j.                  t0        j2                  j5                  |j6                               y )	Nr=   r[  r\     )	chunksizer]  r   )r>  r  r3  )rv  r~  r  r  rI  ru  rK  r?   r  r   r   imap_unorderedr   r;  rT  rh  r  rl   re  rf  rc  rX  r^  r_  r)   r+   r`  r  )r  r>  r3  poolrv  r  r  ra  rg  _r,  rb  r<  rc  s                 r,   multi_threaded_tilingrk  E  s    '',1L/0,ZPD,34??7=='L(9:! As3L 1\ ABCI   $' !  - w}}**,	- ==$T*KK45??(3E(:%%++-TZZ4 54WmTR3sC(8$9\$IJK	$$$+"  % 

 	5A ??7==%224	55" MM"''//$--01r-   c                       e Zd Zd Zd Zy)UseExceptionsc                 x    t        j                         | _        | j                  st        j                          y y r7   )r   GetUseExceptionsold_used_exceptionsrm  r]   s    r,   	__enter__zUseExceptions.__enter__}  s-    #'#8#8#: ''  (r-   c                 F    | j                   st        j                          y y r7   )rp  r   DontUseExceptionsr:   rm  r  r  s       r,   __exit__zUseExceptions.__exit__  s    ''""$ (r-   N)rB   rC   rD   rq  ru  rF   r-   r,   rm  rm  |  s    !
%r-   rm  c                       e Zd Zd Zd Zd Zy)DividedCachec                     || _         y r7   )rv  )r:   rv  s     r,   r;   zDividedCache.__init__  s
    (r-   c                     t        j                         | _        t        dt	        j
                  | j                  | j                  z              }t        |       y )Ni   )r   r  gdal_cache_maxr   r   r   rv  r  )r:   gdal_cache_max_per_processs     r,   rq  zDividedCache.__enter__  sH    "..0%(D$7$7$:K:K$KL&
" 	01r-   c                 .    t        | j                         y r7   )r  rz  rt  s       r,   ru  zDividedCache.__exit__  s    d))*r-   N)rB   rC   rD   r;   rq  ru  rF   r-   r,   rw  rw    s    )2+r-   rw  c                 6   t        t        |             D ]<  }| |   dk(  s|dz   t        |       k  s| |dz      t        j                  | |dz      <   > d| v rddlm} ddlm} t               5   ||j                  d      5 }|	 d d d        d d d        yt        |j                  d	
      |_        t        | ||j                  j                         |      cd d d        cd d d        S t        | |      S # 1 sw Y   nxY wd d d        y # 1 sw Y   y xY w)Nz--configr`   r=   rw  r   )MPI)MPICommExecutor)rootT)	unorderedr  )rl   r?   r)   r  mpi4pyr~  mpi4py.futuresr  rm  
COMM_WORLDr   ry  rh  submainGet_size)r  r  rn   r~  r  ri  s         r,   mainr    s    3t9 27j QUSY%6&*1q5kBJJtAE{#2 $2_ 	ocnn1E 	|	 	 	 #*$((d"CDdCNN335HX	 	 	 t.>??	 	 	 	 	s1   .DC:DAC:	D:D	?DDc           	         t        j                  |       } | yt        | dd  |      \  }}}|r||_        |j                  xs d}t	               5  |t        ||||       nd|dk(  rt        |||       nQdd l}t        |d      sd |_	        ddl
m}	 t        |      5   |	|      5 }t        ||||       d d d        d d d        d d d        y# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   yxY w)Nr   r=   r  __spec__)Pool)r  )r   GeneralCmdLineProcessorr  rv  rm  rk  rd  __main__r  r  multiprocessingr  rw  )
r  ri  	pool_sizer  r  r>  r3  rv  r  r  s
             r,   r  r    s	   ''-D|)5QR#3*&Jw ('',1L	 P!*mWdKQ":}gF 8Z0$(!,l+ PTL-I PT%j-$OP PP" P P P PP" s=   AC'
C'C6C>C'CCC$	 C''C0r  r  )r   r7   )r  r	  r2  r
  rR   N)F)Nr   F)|
__future__r   
contextlibglobjsonr  r   r  r)   r^  r0   r  r  	threading	functoolsr   typingr   r   r   r   r	   uuidr
   	xml.etreer   osgeor   r   rG  rN  PILr   osgeo.gdal_array
gdal_arrayrQ  rM  ImportErrorr  r  r  	getLoggerr  r*   r2   r5   contextmanagerrK   r(   rM   objectrQ   r  r  rB  r8   r+   r`  r
  tmsfilenamerJ   rC  r  loadsr  r~   errorr   r   rT   r   localr  __doc__globalmaptilesr   r   r   r   r  r   r  ra   r  r@  rs  Datasetr   r  r   r  r  r   r  r  r  r  r  r  r  r  r;  rX  rc  rh  r  r  r  r  r
  r	  r  r.  rI  rK  r0  rd  rk  rm  rw  r  r  r  rB   r  rF   r-   r,   <module>r     s  N         	   
    7 7  ! 
	(O
  M			<	()$	K 	K # #	y 	zF zz 
1 4==!9:ggooh'G tyyg|!DE ,K&++-	

4;;w/0A 9LL;67	%%a(C "%s~~CNN+#,& ioo @ XV Xv^(V ^(B5
f 5
p		 	S 3  %# %$ % AECLcL w 4PU; B $<< $*1 $
8C(()8C=89 $F,,-8?c""#.dll t  "&	C,,Cs++,C S))*C g	C
 
\\CL30 "&,,;, g, 
\\	,^63S 63S 63t DH/7/@	\\04<< C IXUUU38_%U U !	U
 Up,,!$,5B,	$uS#X
 ,: # `x,, `F).tCy ).U3WCT=U ).X<<"%<69<<~G G:"4& "4J	i 	J# J#ZF''$''29'
;Z(()'.& .1h+2+2$'+229+2	+2\4242$'422942	42n%F %+6 +" 88e @tCy @ @6$s) PS H zCHHT#((T23 eL  On  	A	 ( 	 	LL;67	s<   "Q( !Q6:R(Q32Q36R RR(R('R(