source: GCLiveMapGen.py @ 05b2faa758a4eb9e6ef73a78dbe1f601eeb22ff1

Revision 05b2faa758a4eb9e6ef73a78dbe1f601eeb22ff1, 68.1 KB checked in by HD Stich <hd@…>, 21 months ago (diff)

Added map server url for OutdoorActive?.com.

  • Property mode set to 100644
Line 
1#!/usr/bin/env python
2#
3# GCLiveMapGen.py - Map Database Generator for the Geocaching Live application.
4#
5# Copyright (C) 2009 HD Stich <hd@palmtopia.de>
6#
7# This program is free software; you can redistribute it and/or modify it under
8# the terms of the GNU General Public License as published by the Free Software
9# Foundation; version 2 only.
10#
11# This program is distributed in the hope that it will be useful, but WITHOUT
12# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License along with
16# this program; if not, see <http://www.gnu.org/licenses/>.
17#
18from math import radians, cos, sin, log, tan, pi
19from PyQt4 import QtGui, QtCore, QtWebKit
20import optparse
21import os
22import re
23import struct
24import sys
25import time
26import urllib
27
28
29version = "0.2.2.1"
30       
31verbosity = 1
32
33mapServersURLs = { "mapnik"     : "http://tile.openstreetmap.org/",
34                   "osmarender" : "http://tah.openstreetmap.org/Tiles/tile/",
35                   "cyclemap"   : "http://andy.sandbox.cloudmade.com/tiles/cycle/",
36                   "osmctopo"   : "http://topo.geofabrik.de/trails/",
37                                   "oagermany"  : "http://t0.outdooractive.com/portal/map/" }
38
39mapServerNames = { "Mapnik"                                       : "mapnik",   
40                   "Osmarender"                                   : "osmarender",
41                   "Cyclemap"                                     : "cyclemap", 
42                   "OSMC Topographic"                             : "osmctopo",
43                                   "OutdoorActive.com (Germany only)" : "oagermany" }
44
45maxZoomLevels = { "mapnik"     : 17,
46                  "osmarender" : 17,
47                  "cyclemap"   : 17,
48                  "osmctopo"   : 15,
49                                  "oagermany"  : 17 }
50
51maxTilesSupported = 0xFFFF
52
53supportedModes = ( "fetch", "generate", "tiles-count", "auto-radius", "gui" )
54
55path2LogDir         = "./"
56isLoggingEnabled    = False
57
58
59def latlon2tileXY( latDeg, lonDeg, zoom ):
60    latRad = radians( latDeg )
61   
62    n = 2.0 ** zoom
63
64    xTile = int( (lonDeg + 180.0) / 360.0 * n )
65    yTile = int( ( 1.0 - log( tan( latRad ) + ( 1 / cos( latRad ) ) ) / pi ) / 2.0 * n )
66   
67    return ( xTile, yTile )
68
69
70def writeMapDB( fh, zoom, x, y, offset, size, index ):
71   
72    #
73    # Zoom.
74    #
75    invZ = 17 - int( zoom )
76    b1Zoom = (invZ >> 8) & 0xFF
77    b2Zoom = invZ & 0xFF
78   
79    #
80    # Tile X.
81    #
82    b1X = (x >> 16) & 0xFF
83    b2X = (x >>  8) & 0xFF
84    b3X = x & 0xFF
85   
86    #
87    # Tile Y.
88    #
89    b1Y = (y >> 16) & 0xFF
90    b2Y = (y >>  8) & 0xFF
91    b3Y = y & 0xFF
92   
93    #
94    # Offset.
95    #
96    b1Offset = (offset >> 24) & 0xFF
97    b2Offset = (offset >> 16) & 0xFF
98    b3Offset = (offset >>  8) & 0xFF
99    b4Offset = offset & 0xFF
100   
101    #
102    # Size and index.
103    #
104    si = ((size << 12) & 0xFFFFF000) | (index & 0xFFF)
105   
106    b1SI = (si >> 24) & 0xFF
107    b2SI = (si >> 16) & 0xFF
108    b3SI = (si >>  8) & 0xFF
109    b4SI = si & 0xFF
110   
111    #
112    # Pack the bytes together.
113    #
114    packedString = "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c" %( b1Zoom, b2Zoom,
115                                                         b1X, b2X, b3X,
116                                                         b1Y, b2Y, b3Y,
117                                                         b1Offset, b2Offset, b3Offset, b4Offset,
118                                                         b1SI, b2SI, b3SI, b4SI )
119   
120    #
121    # Write to DB file.
122    #
123    fh.write( packedString )
124       
125
126def writeMapDBHeader( fh, index, dbSize, tiles, currentDataFileSize ):
127   
128    seekMapDB( fh, 0 )
129   
130    packedBuffer = struct.pack( ">4I", index, dbSize, tiles, currentDataFileSize )
131   
132    fh.write( packedBuffer )
133
134
135def finishMapDBGeneration( mapDBDir, tilesCounter, currentDataIndex,
136                           currentDataDirIndex, mapDBHandle, dataFileHandle ):
137   
138    closeDataFile( dataFileHandle )
139    dataFileStat = os.stat( os.path.normpath( os.path.join( mapDBDir, str( currentDataDirIndex ),
140                                                            "data" + str( currentDataIndex ) ) ) )
141    writeMapDBHeader( mapDBHandle, currentDataIndex, tilesCounter,
142                      tilesCounter, dataFileStat.st_size )
143    closeMapDB( mapDBHandle )
144   
145    if verbosity > 0:
146        print "\nGenerated GC Live Map DB with %d tiles.\n" % (tilesCounter)
147       
148        baseName = os.path.basename( mapDBDir )
149       
150        print "Your offline map is saved in:\n\n" \
151              "  %s\n\n" \
152              "Copy contents of this directory onto your memory card into directory:\n\n" \
153              "  e:\\trackonfly\\map\\%s\n\n" \
154              "If you are using Windows Mobile, copy into:\n\n" \
155              "  <GC Live installation directory>\\map\\%s\n\n" \
156              "Have fun! :)" \
157              % (mapDBDir, baseName, baseName)
158       
159
160def generateMapDB( tilesDir, zoomLevels, mapDBDir, boundingBox, maxTiles ):
161   
162    minLat, minLon, maxLat, maxLon = getCoordsFromBoundingBox( boundingBox )
163   
164    #
165    # Counts the number of PNGs in a data file.
166    #
167    pngCounter = 0
168   
169    #
170    # Counts the total number of PNG tiles.
171    #
172    tilesCounter = 0
173   
174    #
175    # Counts the number of data files in the current output directory.
176    #
177    dataFileCounter = 0
178   
179    #
180    # Current index for the data files.
181    #
182    currentDataIndex = 0
183   
184    #
185    # Current index for the data file directories.
186    #
187    currentDataDirIndex = 0
188   
189    dataFileOffset = 0
190   
191    createMapDBDir( mapDBDir )
192   
193    mapDBHandle = openMapDB( mapDBDir )
194   
195    #
196    # Seek over header.
197    #
198    seekMapDB( mapDBHandle, 16 + currentDataIndex * 16 )
199   
200    createDataDir( mapDBDir, currentDataDirIndex )
201   
202    dataFileHandle = openDataFile( mapDBDir, currentDataDirIndex, currentDataIndex )
203   
204    #
205    # Loop over all PNG files.
206    #
207   
208    for zoom in reversed( zoomLevels ):
209       
210        zoomDir = str( zoom )
211   
212        if verbosity > 0:
213            print "Parsing zoom level %d..." % (zoom)
214       
215        (minXTile, minYTile) = latlon2tileXY( minLat, minLon, zoom )
216        (maxXTile, maxYTile) = latlon2tileXY( maxLat, maxLon, zoom )
217       
218        for xTile in xrange( minXTile, maxXTile + 1 ):
219           
220            xTilesDir = str( xTile )
221           
222            for yTile in xrange( maxYTile, minYTile + 1 ):
223           
224                QtGui.QApplication.processEvents()
225                   
226                pngName = str( yTile ) + ".png"
227                   
228                pngPath = os.path.normpath( os.path.join( tilesDir, zoomDir, xTilesDir, pngName ) )
229       
230                if os.path.exists( pngPath ):
231                   
232                    if verbosity > 1:
233                        print "Using %s" % (pngPath)
234
235                    pngStat = os.stat( pngPath )
236                   
237                    pngHandle = open( pngPath, "rb" )
238                    dataFileHandle.write( pngHandle.read() )
239                    pngHandle.close()
240               
241                    writeMapDB( mapDBHandle, zoom, xTile, yTile, dataFileOffset, pngStat.st_size, currentDataIndex )
242                   
243                    pngCounter      += 1
244                    tilesCounter    += 1
245                    dataFileOffset  = dataFileOffset    + pngStat.st_size
246                   
247                    if tilesCounter >= maxTiles:
248                        print "Reached max. tiles count (%d), exiting..." % (maxTiles)
249                       
250                        finishMapDBGeneration( mapDBDir, tilesCounter, currentDataIndex,
251                                               currentDataDirIndex, mapDBHandle, dataFileHandle )
252                        return 0
253                   
254                    if pngCounter >= 32:
255                        pngCounter = 0
256                       
257                        closeDataFile( dataFileHandle )
258                       
259                        dataFileOffset = 0
260                       
261                        dataFileCounter     += 1
262                        currentDataIndex    += 1
263                       
264                        if dataFileCounter >= 32:
265                            dataFileCounter = 0
266                           
267                            currentDataDirIndex += +1
268                            createDataDir( mapDBDir, currentDataDirIndex )
269                           
270                            dataFileHandle = openDataFile( mapDBDir, currentDataDirIndex, currentDataIndex )
271                        else:
272                            dataFileHandle = openDataFile( mapDBDir, currentDataDirIndex, currentDataIndex )
273
274        if verbosity > 0:
275            print "Packed %d files ..." % (tilesCounter)
276
277    #
278    # Write header and close the map database.
279    #
280
281    finishMapDBGeneration( mapDBDir, tilesCounter, currentDataIndex,
282                           currentDataDirIndex, mapDBHandle, dataFileHandle)
283
284
285def closeDataFile( dataFileHandle ):
286   
287    dataFileHandle.close()
288
289   
290def openDataFile( dirName, dirIndex, fileIndex ):
291   
292    fileName = os.path.join( dirName, str( dirIndex ), "data" + str( fileIndex ) )
293   
294    try:
295        dataFileHandle = open( fileName, "wb" )
296    except IOError:
297        print "WARNING: Could not create data file '%s'!" % (fileName)
298       
299    return dataFileHandle
300           
301
302def createDataDir( dirName, index ):
303   
304    dirName = os.path.join( dirName, str( index ) )
305   
306    if os.path.exists( dirName ) == False:
307        try:
308            os.mkdir( dirName )
309        except OSError:
310            print "WARNING: Could not create data dirName '%s'!" % (dirName)
311           
312
313def createMapDBDir( dirName ):
314   
315    dfPattern = re.compile( r"data\d+" )
316    ddPattern = re.compile( r"\d+" )
317   
318    if os.path.exists( dirName ) == False:
319        try:
320            os.makedirs( dirName )
321        except OSError:
322            print "WARNING: Could not create map dirName '%s'!" % (dirName)
323    else:
324        for root, dirs, files in os.walk( dirName, topdown = False ):
325           
326            for name in files:
327                if dfPattern.search( name ) != None:
328                    os.remove( os.path.join( root, name ) )
329                    continue
330                   
331                if name == "index":
332                    os.remove( os.path.join( root, name ) )
333               
334            for name in dirs:
335                if ddPattern.search( name ) != None:
336                    try:
337                        os.rmdir( os.path.join( root, name ) )
338                    except OSError:
339                        print "WARNING: Hmm, are you sure that '%s' is a GC Live Map DB directory?" % (dirName)
340                        return 1
341           
342       
343def seekMapDB( dbHandle, offset ):
344    try:
345        dbHandle.seek( offset )
346    except IOError:
347        print "WARNING: Could't seek DB file!"
348       
349       
350def openMapDB( dirName ):
351   
352    try:
353        mapDBHandle = open( os.path.join( dirName, "index" ), "wb" )
354    except IOError:
355        print "WARNING: Could not open DB file!"
356
357    try:
358        mapDBHandle.seek( 15 )
359    except IOError:
360        print "WARNING: Could not seek DB file!"
361
362    try:
363        mapDBHandle.write( '\0' )
364    except IOError:
365        print "WARNING: Could not write DB file!"
366
367    return mapDBHandle
368
369
370def closeMapDB( dbHandle ):
371   
372    dbHandle.close()
373   
374   
375def getBoundingBoxFormat( boundingBox ):
376   
377    fPattern = re.compile( r"^(.+?)://.+$" )
378   
379    sr = fPattern.search( boundingBox )
380   
381    if sr == None:
382        bbFormat = "default"
383    else:
384        bbFormat = sr.group( 1 )
385       
386    return bbFormat
387
388
389def calcBoundingBoxCoords( lat, lon, radius, angle ):
390   
391    dNorth  = cos( radians( angle ) ) * radius
392    dEast   = sin( radians( angle ) ) * radius
393
394    dLat = dNorth / (1850 * 60)
395    dLon = dEast / ((1850 * 60) * cos( radians( lat ) ))
396   
397    projLat = lat + dLat
398    projLon = lon + dLon
399   
400    return (projLat, projLon)   
401   
402   
403def getCoordsFromBoundingBox( boundingBox ):
404   
405    boundingBoxFormat = getBoundingBoxFormat( boundingBox )
406
407    if boundingBoxFormat == "http":
408        sp = re.compile( r"^http://.+lat=([-+\d.]+)&lon=([-+\d.]+)&zoom=(\d+).*:([\d.]+)$" )
409       
410        sr = sp.search( boundingBox )
411       
412        if sr != None:
413            try:
414                lat     = float( sr.group( 1 ) )
415                lon     = float( sr.group( 2 ) )
416                radius  = float( sr.group( 4 ) ) * 1000
417               
418            except:
419                #pylint: disable-msg=W0702
420                sys.exit( "WARNING: Bounding box '%s' is in a wrong format!" % (boundingBox) )
421
422            projLat, projLon = calcBoundingBoxCoords( lat, lon, radius, 180 )
423            minLat = projLat
424                       
425            projLat, projLon = calcBoundingBoxCoords( lat, lon, radius, 0 )
426            maxLat = projLat
427                       
428            projLat, projLon = calcBoundingBoxCoords( lat, lon, radius, 270 )
429            minLon = projLon
430                       
431            projLat, projLon = calcBoundingBoxCoords( lat, lon, radius, 90 )
432            maxLon = projLon
433                       
434        else:
435            sys.exit( "WARNING: Bounding box '%s' is in a wrong format!" % (boundingBox) )
436       
437    elif boundingBoxFormat == "radius":
438        sp = re.compile( r"radius://([\d.]+):([-+\d.]+):([-+\d.]+)$" )
439       
440        sr = sp.search( boundingBox )
441       
442        if sr != None:
443            try:
444                radius  = float( sr.group( 1 ) ) * 1000
445                lat     = float( sr.group( 2 ) )
446                lon     = float( sr.group( 3 ) )
447               
448            except:
449                #pylint: disable-msg=W0702
450                sys.exit( "WARNING: Bounding box '%s' is in a wrong format!" % (boundingBox) )
451               
452            projLat, projLon = calcBoundingBoxCoords( lat, lon, radius, 180 )
453            minLat = projLat
454                       
455            projLat, projLon = calcBoundingBoxCoords( lat, lon, radius, 0 )
456            maxLat = projLat
457                       
458            projLat, projLon = calcBoundingBoxCoords( lat, lon, radius, 270 )
459            minLon = projLon
460                       
461            projLat, projLon = calcBoundingBoxCoords( lat, lon, radius, 90 )
462            maxLon = projLon
463           
464        else:
465            sys.exit( "WARNING: Bounding box '%s' is in a wrong format!" % (boundingBox) )
466       
467    elif boundingBoxFormat == "box":
468        sp = re.compile( r"box://([-+\d.]+):([-+\d.]+):([-+\d.]+):([-+\d.]+)$" )
469       
470        sr = sp.search( boundingBox )
471       
472        if sr != None:
473            try:
474                minLat  = float( sr.group( 1 ) )
475                minLon  = float( sr.group( 2 ) )
476                maxLat  = float( sr.group( 3 ) )
477                maxLon  = float( sr.group( 4 ) )
478               
479            except ValueError:
480                sys.exit( "WARNING: Bounding box '%s' is in a wrong format!" % (boundingBox) )
481           
482        else:
483            sys.exit( "WARNING: Bounding box '%s' is in a wrong format!" % (boundingBox) )
484       
485    else:
486        try:
487            minLat = float( boundingBox.split( ":" )[0] )
488            minLon = float( boundingBox.split( ":" )[1] )
489           
490            maxLat = float( boundingBox.split( ":" )[2] )
491            maxLon = float( boundingBox.split( ":" )[3] )
492           
493        except ValueError:
494            sys.exit( "WARNING: Bounding box '%s' is in a wrong format!" % (boundingBox) )
495   
496    #
497    # Fixes ticket #2 - Bounding box coords in wrong order.
498    #
499    if minLat > maxLat:
500        minLat, maxLat = maxLat, minLat
501        if verbosity > 0:
502            print "Latitudes have been in wrong order, exchanged it automagically!"
503
504    if minLon > maxLon:
505        minLon, maxLon = maxLon, minLon
506        if verbosity > 0:
507            print "Longitudes have been in wrong order, exchanged it automagically!"
508
509    return (minLat, minLon, maxLat, maxLon)
510
511
512def calcNumberMapTiles( boundingBox, zoomLevels ):
513   
514    minLat, minLon, maxLat, maxLon = getCoordsFromBoundingBox( boundingBox )
515   
516    mapTilesCount = 0
517   
518    for zoom in zoomLevels:
519        minTileX, minTileY = latlon2tileXY( minLat, minLon, zoom )
520        maxTileX, maxTileY = latlon2tileXY( maxLat, maxLon, zoom )
521       
522        tileXDiff = (maxTileX - minTileX) + 1
523        tileYDiff = (minTileY - maxTileY) + 1
524       
525        mapTilesCount += tileXDiff * tileYDiff
526       
527    return mapTilesCount
528
529
530def fetchOSMTiles( tilesDir, osmMapServer, boundingBox, zoomLevels, updateTiles, pausing, maxTiles ):
531   
532    if (verbosity > 0) and (updateTiles == True):
533        print "Fetch will update already existing tiles."
534
535    estTilesCount = calcNumberMapTiles( boundingBox, zoomLevels )
536
537    if verbosity > 0:
538        print "Estimated tiles count: %d" % (estTilesCount)
539       
540    if estTilesCount > maxTiles:
541        print "WARNING: Estimated tiles count (%d) is greater than given max. tiles count (%d), exiting...!" % \
542              (estTilesCount, maxTiles)
543        return 1
544   
545    tilesCountStr, waitingTimeStr = pausing.split( ":" )
546   
547    mapTilesCount   = int( tilesCountStr )
548    waitingTime     = int( waitingTimeStr )
549   
550    if os.path.isdir( tilesDir ) == False:
551        os.makedirs( tilesDir )
552
553    baseURL = mapServersURLs[osmMapServer]
554
555    minLat, minLon, maxLat, maxLon = getCoordsFromBoundingBox( boundingBox )
556
557    if verbosity > 0:
558        bbFormat = getBoundingBoxFormat( boundingBox )
559        print "Bounding box bbFormat: %s" % (bbFormat)
560        print "Bounding box coords: %.4f:%.4f:%.4f:%.4f" % (minLat, minLon, maxLat, maxLon)
561       
562    tilesCounter        = 0
563    totalTilesChecked   = 0
564    totalTilesFetched   = 0
565    retryCounter        = 0
566   
567    ctPattern = re.compile( r"^Content-Type: (.+)\r$", re.MULTILINE )
568
569    for zoom in zoomLevels:
570       
571        if verbosity > 0:
572            print "Fetching zoom level %s ..." % (zoom)
573           
574        zoomDir = os.path.join( tilesDir, str( zoom ) )
575       
576        if os.path.isdir( zoomDir ) == False:
577            os.mkdir( zoomDir )
578           
579        minTileX, minTileY = latlon2tileXY( minLat, minLon, zoom )
580        maxTileX, maxTileY = latlon2tileXY( maxLat, maxLon, zoom )
581
582        if verbosity > 1:
583            print "Fetching tiles from [%d,%d] to [%d,%d]." % (minTileX, minTileY, maxTileX, maxTileY)
584           
585        for tileX in xrange( minTileX, maxTileX + 1 ):
586           
587            tileXDir = os.path.join( tilesDir, str( zoom ), str( tileX ) )
588           
589            if os.path.isdir( tileXDir ) == False:
590                os.mkdir( tileXDir )
591           
592            for tileY in xrange( maxTileY, minTileY + 1 ):
593               
594                QtGui.QApplication.processEvents()
595               
596                sourceURL   = baseURL + str( zoom ) + "/" + str( tileX ) + "/" + str( tileY ) + ".png"
597                targetPath  = os.path.join( tilesDir, str( zoom ), str( tileX ), str( tileY ) + ".png" )
598               
599                totalTilesChecked += 1
600               
601                if (os.path.exists( targetPath ) == False) or (updateTiles == True):
602   
603                    if verbosity > 1:
604                        print "%s => %s" % (sourceURL, targetPath)
605                       
606                    while retryCounter < 3:
607                        try:
608                            unused_fileName, header = urllib.urlretrieve( sourceURL, targetPath )
609                            break
610                        except IOError:
611                            retryCounter += 1
612                           
613                    if retryCounter >= 3:
614                        print "WARNING: Could not fetch URL '%s'!" % (sourceURL)
615                        retryCounter = 0
616                        continue
617
618                    contentType = ctPattern.search( str( header ) ).group( 1 )
619                   
620                    if contentType != "image/png":
621                        print "WARNING: Fetched file has wrong content type '%s'!" % (contentType)
622                        retryCounter = 0
623                        continue
624                   
625                    retryCounter         = 0
626                    tilesCounter        += 1
627                    totalTilesFetched   += 1
628                   
629                    #if totalTilesFetched >= maxTiles:
630                    #    print "WARNING: Reached max. tiles count (%d), exiting..." % \
631                    #          (maxTiles)
632                    #    return 1
633                   
634                    if tilesCounter >= mapTilesCount:
635                       
636                        if verbosity > 0:
637                            print "Pausing for %d seconds..." % (waitingTime)
638                           
639                        tilesCounter = 0
640                        time.sleep( waitingTime )
641
642                if verbosity > 0:
643                    if (totalTilesChecked % 100) == 0:
644                        print "Checked %d / Fetched %d tiles ..." % (totalTilesChecked, totalTilesFetched)
645               
646    if verbosity > 0:
647        print "Total tiles fetched: %d" % (totalTilesFetched)
648
649
650def tilesCount( boundingBox, zoomLevels ):
651   
652    mapTiles = calcNumberMapTiles( boundingBox, zoomLevels )
653   
654    print "\nBounding box: %s" \
655          "\nEstimated tiles count: %d" % \
656          (boundingBox, mapTiles)
657
658
659def autoRadius( homeCoord, zoomLevels, maxTiles ):
660   
661    radius = 0.0
662   
663    boundingBox = "radius://" + str( radius ) + ":" + homeCoord
664   
665    mapTilesCount = calcNumberMapTiles( boundingBox, zoomLevels )
666   
667    while mapTilesCount <= maxTiles:
668
669        QtGui.QApplication.processEvents()
670               
671        radius += 0.1
672       
673        boundingBox = "radius://" + str( radius ) + ":" + homeCoord
674       
675        mapTilesCount = calcNumberMapTiles( boundingBox, zoomLevels )
676       
677    radius -= 0.1
678   
679    print "\nMax. radius for %d tiles: %.1f km" % (maxTiles, radius)
680
681
682class OutputWidget( QtGui.QPlainTextEdit ):
683   
684    def __init__( self, parent = None ):
685       
686        super( OutputWidget, self ).__init__( parent )
687       
688   
689    def write( self, text ):
690       
691        if text != "\n":
692            self.appendPlainText( text.strip() )
693            self.moveCursor( QtGui.QTextCursor.End )
694       
695       
696class TilesCountPage( QtGui.QWidget ):       
697
698    def __init__( self, parent = None ):
699       
700        super( TilesCountPage, self ).__init__( parent )
701
702        self.startZoomLevel     = None
703        self.endZoomLevel       = None
704        self.boundingBox        = None
705
706        self.readSettings()
707       
708        boundingBoxLineEdit = QtGui.QLineEdit()
709        boundingBoxLineEdit.setText( self.boundingBox )
710        boundingBoxLineEdit.textChanged.connect( self.boundingBoxLineEditChanged )
711
712        startZoomLevelSpinBox = QtGui.QSpinBox()
713        startZoomLevelSpinBox.setValue( self.startZoomLevel )
714        startZoomLevelSpinBox.setRange( 6, 17 )
715        startZoomLevelSpinBox.valueChanged.connect( self.startZoomLevelChanged )
716       
717        endZoomLevelSpinBox = QtGui.QSpinBox()
718        endZoomLevelSpinBox.setValue( self.endZoomLevel )
719        endZoomLevelSpinBox.setRange( 6, 17 )
720        endZoomLevelSpinBox.valueChanged.connect( self.endZoomLevelChanged )
721       
722        layout = QtGui.QGridLayout()
723        layout.addWidget( QtGui.QLabel( "Bounding Box:" ), 0, 0 )
724        layout.addWidget( boundingBoxLineEdit, 1, 0 )
725        layout.addWidget( QtGui.QLabel( "Start zoom level:" ), 2, 0 )
726        layout.addWidget( startZoomLevelSpinBox, 3, 0 )
727        layout.addWidget( QtGui.QLabel( "End zoom level:" ), 4, 0 )
728        layout.addWidget( endZoomLevelSpinBox, 5, 0 )
729        layout.addWidget( QtGui.QLabel( "" ), 6, 0 )
730        layout.setRowStretch( 6, 1 )
731       
732        self.setLayout( layout )
733       
734                 
735    def readSettings( self ):
736       
737        settings = QtCore.QSettings()
738       
739        settings.beginGroup( "tiles-count" )
740       
741        self.startZoomLevel = settings.value( "startZoomLevel", 6 ).toInt()
742        if type( self.startZoomLevel ) is not int:
743            self.startZoomLevel = self.startZoomLevel[0]
744           
745        self.endZoomLevel   = settings.value( "endZoomLevel", 17 ).toInt()
746        if type( self.endZoomLevel ) is not int:
747            self.endZoomLevel = self.endZoomLevel[0]
748       
749        self.boundingBox    = settings.value( "boundingBox", "radius://22.3:48.25:9.55" ).toString()
750       
751        settings.endGroup()
752
753   
754    def writeSettings( self ):
755       
756        settings = QtCore.QSettings()
757       
758        settings.beginGroup( "tiles-count" )
759       
760        settings.setValue( "startZoomLevel",   self.startZoomLevel )
761        settings.setValue( "endZoomLevel",     self.endZoomLevel ) 
762        settings.setValue( "boundingBox",      self.boundingBox )   
763       
764        settings.endGroup()
765       
766   
767    def boundingBoxLineEditChanged( self, text ):
768       
769        self.boundingBox = text
770       
771        self.writeSettings()
772       
773
774    def startZoomLevelChanged( self, value ):
775       
776        self.startZoomLevel = value
777       
778        self.writeSettings()
779       
780
781    def endZoomLevelChanged( self, value ):
782       
783        self.endZoomLevel = value
784
785        self.writeSettings()
786       
787
788class MyDoubleValidator( QtGui.QDoubleValidator ):
789   
790    def __init__( self, parent = None ):
791       
792        super( MyDoubleValidator, self ).__init__( parent )
793       
794        self.currentLocale = QtCore.QLocale.system()
795       
796       
797    def validate( self, text, pos ):
798       
799        if (len( text ) == 0) or (text == self.currentLocale.decimalPoint()) or (text == "-") or (text == "+"):
800            return (QtGui.QValidator.Intermediate, pos)
801       
802        elif QtGui.QDoubleValidator.validate( self, text, pos )[0] != QtGui.QValidator.Acceptable:
803            return (QtGui.QValidator.Invalid, pos)
804       
805        else:
806            return (QtGui.QValidator.Acceptable, pos)
807
808
809class AutoRadiusPage( QtGui.QWidget ):       
810
811    def __init__( self, parent = None ):
812       
813        super( AutoRadiusPage, self ).__init__( parent )
814       
815        self.latitude       = None
816        self.longitude      = None
817        self.startZoomLevel = None
818        self.endZoomLevel   = None
819        self.maxTiles       = None
820
821        self.readSettings()
822       
823        #
824        # Validators
825        #
826
827        latValidator = MyDoubleValidator()
828        latValidator.setNotation( QtGui.QDoubleValidator.StandardNotation )
829        latValidator.setRange( -85.0511, +85.0511, 4 )
830       
831        lonValidator = MyDoubleValidator()
832        lonValidator.setNotation( QtGui.QDoubleValidator.StandardNotation )
833        lonValidator.setRange( -180.0, +180.0, 4 )
834
835        maxTilesValidator = QtGui.QIntValidator( 1, 65535, self )
836
837        latLineEdit = QtGui.QLineEdit()
838        latLineEdit.setText( self.latitude )
839        latLineEdit.setValidator( latValidator )
840        latLineEdit.textChanged.connect( self.latLineEditChanged )
841       
842        lonLineEdit = QtGui.QLineEdit()
843        lonLineEdit.setText( self.longitude )
844        lonLineEdit.setValidator( lonValidator )
845        lonLineEdit.textChanged.connect( self.lonLineEditChanged )
846       
847        startZoomLevelSpinBox = QtGui.QSpinBox()
848        startZoomLevelSpinBox.setValue( self.startZoomLevel )
849        startZoomLevelSpinBox.setRange( 6, 17 )
850        startZoomLevelSpinBox.valueChanged.connect( self.startZoomLevelChanged )
851       
852        endZoomLevelSpinBox  = QtGui.QSpinBox()
853        endZoomLevelSpinBox.setValue( self.endZoomLevel )
854        endZoomLevelSpinBox.setRange( 6, 17 )
855        endZoomLevelSpinBox.valueChanged.connect( self.endZoomLevelChanged )
856       
857        maxTilesLineEdit = QtGui.QLineEdit()
858        maxTilesLineEdit.setText( self.maxTiles )
859        maxTilesLineEdit.setValidator( maxTilesValidator )
860        maxTilesLineEdit.textChanged.connect( self.maxTilesLineEditChanged )
861       
862        layout = QtGui.QGridLayout()
863        layout.addWidget( QtGui.QLabel( "Latitude:" ), 0, 0 )
864        layout.addWidget( QtGui.QLabel( "Longitude:" ), 0, 1 )
865        layout.addWidget( latLineEdit, 1, 0 )
866        layout.addWidget( lonLineEdit, 1, 1 )
867        layout.addWidget( QtGui.QLabel( "Start zoom level:" ), 2, 0 )
868        layout.addWidget( startZoomLevelSpinBox, 3, 0, 1, 2 )
869        layout.addWidget( QtGui.QLabel( "End zoom level:" ), 4, 0 )
870        layout.addWidget( endZoomLevelSpinBox, 5, 0, 1, 2 )
871        layout.addWidget( QtGui.QLabel( "Max. tiles:" ), 6, 0 )
872        layout.addWidget( maxTilesLineEdit, 7, 0, 1, 2 )
873        layout.addWidget( QtGui.QLabel( "" ), 8, 0 )
874        layout.setRowStretch( 8, 1 )
875
876        self.setLayout( layout )
877
878
879    def readSettings( self ):
880       
881        settings = QtCore.QSettings()
882       
883        settings.beginGroup( "auto-radius" )
884       
885        self.latitude       = settings.value( "latitude", "48.25" ).toString()
886        self.longitude      = settings.value( "longitude", "9.55" ).toString()
887       
888        self.startZoomLevel = settings.value( "startZoomLevel", 6 ).toInt()
889        if type( self.startZoomLevel ) is not int:
890            self.startZoomLevel = self.startZoomLevel[0]
891           
892        self.endZoomLevel   = settings.value( "endZoomLevel", 17 ).toInt()
893        if type( self.endZoomLevel ) is not int:
894            self.endZoomLevel = self.endZoomLevel[0]
895       
896        self.maxTiles       = settings.value( "maxTiles", str( maxTilesSupported ) ).toString()
897       
898        settings.endGroup()
899
900   
901    def writeSettings( self ):
902       
903        settings = QtCore.QSettings()
904       
905        settings.beginGroup( "auto-radius" )
906       
907        settings.setValue( "latitude",          self.latitude )
908        settings.setValue( "longitude",         self.longitude )
909        settings.setValue( "startZoomLevel",    self.startZoomLevel )
910        settings.setValue( "endZoomLevel",      self.endZoomLevel ) 
911        settings.setValue( "maxTiles",          self.maxTiles )
912       
913        settings.endGroup()
914       
915   
916    def startZoomLevelChanged( self, value ):
917       
918        self.startZoomLevel = value
919       
920        self.writeSettings()
921       
922
923    def endZoomLevelChanged( self, value ):
924       
925        self.endZoomLevel = value
926       
927        self.writeSettings()
928       
929
930    def maxTilesLineEditChanged( self, text ):
931       
932        self.maxTiles = text
933       
934        self.writeSettings()
935       
936   
937    def latLineEditChanged( self, text ):
938       
939        self.latitude = text
940       
941        self.writeSettings()
942       
943   
944    def lonLineEditChanged( self, text ):
945       
946        self.longitude = text
947
948        self.writeSettings()
949       
950
951class MapSelectorWidget( QtGui.QDialog ):
952
953    def __init__( self, parent = None ):
954
955        super( MapSelectorWidget, self ).__init__( parent )
956
957        self.setWindowTitle( " GCLiveMapGen Map Selector" )
958        self.setWindowIcon( QtGui.QIcon( "icons/GC.ico" ) )
959       
960        screen  = QtGui.QDesktopWidget().screenGeometry()
961        self.resize( screen.width() - 50, screen.height() - 50 )
962        self.center()
963       
964        self.webView = QtWebKit.QWebView()
965        self.webView.load( QtCore.QUrl( "http://www.openstreetmap.org/" ) )
966        self.webPage = self.webView.page()
967
968        okButton = QtGui.QPushButton( "OK" )
969        okButton.clicked.connect( self.accept )
970       
971        quitButton = QtGui.QPushButton( "Quit" )
972        quitButton.clicked.connect( self.reject )
973       
974        hBox = QtGui.QHBoxLayout()
975        hBox.addStretch()
976        hBox.addWidget( okButton )
977        hBox.addWidget( quitButton )
978       
979        layout = QtGui.QVBoxLayout()
980        layout.addWidget( self.webView )
981        layout.addLayout( hBox )
982       
983        self.setLayout( layout )
984       
985       
986    def okButtonClicked( self ):
987       
988        self.close()
989
990
991    def quitButtonClicked( self ):
992       
993        self.close()
994
995
996    def center( self ):
997       
998        screen  = QtGui.QDesktopWidget().screenGeometry()
999        size    = self.frameSize()
1000       
1001        self.move( (screen.width() - size.width()) / 2, (screen.height() - size.height()) / 2 )
1002       
1003       
1004class GetDirNameWidget( QtGui.QWidget, QtCore.QObject ):
1005       
1006    path2DirChanged = QtCore.pyqtSignal( QtCore.QString )
1007       
1008    def __init__( self, caption, path2Dir, parent = None ):
1009       
1010        super( GetDirNameWidget, self ).__init__( parent )
1011       
1012        self.caption    = caption
1013        self.path2Dir   = path2Dir
1014
1015        self.path2DirLineEdit = QtGui.QLineEdit()
1016        self.path2DirLineEdit.setText( self.path2Dir )
1017        self.path2DirLineEdit.textChanged.connect( self.path2DirTextChanged )
1018       
1019        browse2DirPushButton = QtGui.QPushButton( "Browse ..." )
1020        browse2DirPushButton.clicked.connect( self.browse2DirClicked )
1021
1022        layout = QtGui.QHBoxLayout()
1023        layout.addWidget( self.path2DirLineEdit )
1024        layout.addWidget( browse2DirPushButton )
1025        layout.setMargin( 0 )
1026       
1027        self.setLayout( layout )
1028               
1029   
1030    def path2DirTextChanged( self, text ):
1031       
1032        self.path2Dir = text
1033        self.path2DirChanged.emit( text )
1034       
1035       
1036    def browse2DirClicked( self ):
1037       
1038        fileDialog = QtGui.QFileDialog()
1039       
1040        dirName = fileDialog.getExistingDirectory( self, self.caption, self.path2Dir )
1041       
1042        if len( dirName ) > 0:
1043            self.path2Dir = dirName
1044            self.path2DirLineEdit.setText( dirName )
1045            self.path2DirChanged.emit( dirName )
1046       
1047       
1048class FetchPage( QtGui.QWidget ):       
1049
1050    def __init__( self, parent = None ):
1051       
1052        super( FetchPage, self ).__init__( parent )
1053       
1054        self.path2TilesDir  = None
1055        self.path2MapDBDir  = None
1056        self.mapServer      = None
1057        self.startZoomLevel = None
1058        self.endZoomLevel   = None
1059        self.updateTiles    = None
1060        self.tilesCount     = None
1061        self.waitFor        = None
1062        self.maxTiles       = None
1063        self.boundingBox    = None
1064       
1065        self.readSettings()
1066       
1067        #
1068        # Validators
1069        #
1070
1071        maxTilesValidator   = QtGui.QIntValidator( 1, 65535, self )
1072        tilesCountValidator = QtGui.QIntValidator( 1, 1000, self )
1073        waitForValidator    = QtGui.QIntValidator( 3, 10, self )
1074
1075        path2TilesDirWidget = GetDirNameWidget( "Browse to tiles directory:", self.path2TilesDir )
1076        path2TilesDirWidget.path2DirChanged.connect( self.path2TilesDirChanged )
1077       
1078        mapServerComboBox = QtGui.QComboBox()
1079        for mapServerName in sorted( mapServerNames.keys() ):
1080            mapServerComboBox.addItem( mapServerName )
1081        mapServerComboBox.activated[str].connect( self.maxServerComboBoxActivated )
1082        mapServerComboBox.setCurrentIndex( mapServerComboBox.findText( self.mapServer  ) )
1083       
1084        startZoomLevelSpinBox = QtGui.QSpinBox()
1085        startZoomLevelSpinBox.setValue( self.startZoomLevel )
1086        startZoomLevelSpinBox.setRange( 6, 17 )
1087        startZoomLevelSpinBox.valueChanged.connect( self.startZoomLevelChanged )
1088       
1089        self.endZoomLevelSpinBox  = QtGui.QSpinBox()
1090        self.endZoomLevelSpinBox.setValue( self.endZoomLevel )
1091        self.endZoomLevelSpinBox.setRange( 6, 17 )
1092        self.endZoomLevelSpinBox.valueChanged.connect( self.endZoomLevelChanged )
1093       
1094        updateTilesCheckBox = QtGui.QCheckBox()
1095        updateTilesCheckBox.setCheckState( self.updateTiles )
1096        updateTilesCheckBox.setTristate( False )
1097        updateTilesCheckBox.stateChanged.connect( self.updateTilesCheckBoxStateChanged )
1098       
1099        utLayout = QtGui.QHBoxLayout()
1100        utLayout.addWidget( QtGui.QLabel( "Update tiles:" ) )
1101        utLayout.addWidget( updateTilesCheckBox )
1102        utLayout.addStretch( 1 )
1103       
1104        boundingBoxLineEdit = QtGui.QLineEdit()
1105        boundingBoxLineEdit.setText( self.boundingBox )
1106        boundingBoxLineEdit.textChanged.connect( self.boundingBoxLineEditChanged )
1107
1108        maxTilesLineEdit = QtGui.QLineEdit()
1109        maxTilesLineEdit.setText( self.maxTiles )
1110        maxTilesLineEdit.setValidator( maxTilesValidator )
1111        maxTilesLineEdit.textChanged.connect( self.maxTilesLineEditChanged )
1112       
1113        tilesCountLineEdit = QtGui.QLineEdit()
1114        tilesCountLineEdit.setText( self.tilesCount )
1115        tilesCountLineEdit.setValidator( tilesCountValidator )
1116        tilesCountLineEdit.textChanged.connect( self.tilesCountLineEditChanged )
1117       
1118        waitForLineEdit = QtGui.QLineEdit()
1119        waitForLineEdit.setText( self.waitFor )
1120        waitForLineEdit.setValidator( waitForValidator )
1121        waitForLineEdit.textChanged.connect( self.waitForLineEditChanged )
1122       
1123        startMapSelectorButton = QtGui.QPushButton( "Map selector..." )
1124        startMapSelectorButton.setEnabled( False )
1125        startMapSelectorButton.clicked.connect( self.startMapSelectorButtonClicked )
1126       
1127        layout = QtGui.QGridLayout()
1128        layout.addWidget( QtGui.QLabel( "Tiles Directory:" ), 0, 0 )
1129        layout.addWidget( path2TilesDirWidget, 1, 0, 1, 2 )
1130        layout.addWidget( QtGui.QLabel( "Map Server:" ), 2, 0 )
1131        layout.addWidget( mapServerComboBox, 3, 0, 1, 2 )
1132        layout.addWidget( QtGui.QLabel( "Start zoom level:" ), 4, 0 )
1133        layout.addWidget( startZoomLevelSpinBox, 5, 0, 1, 2 )
1134        layout.addWidget( QtGui.QLabel( "End zoom level:" ), 6, 0 )
1135        layout.addWidget( self.endZoomLevelSpinBox, 7, 0, 1, 2 )
1136        layout.addWidget( QtGui.QLabel( "Bounding box:" ), 8, 0 )
1137        layout.addWidget( boundingBoxLineEdit, 9, 0, 1, 2 )
1138        layout.addWidget( QtGui.QLabel( "Max. tiles:" ), 10, 0 )
1139        layout.addWidget( maxTilesLineEdit, 11, 0, 1, 2 )
1140        layout.addLayout( utLayout, 12, 0 )
1141        layout.addWidget( QtGui.QLabel( "After X tiles:" ), 13, 0 )
1142        layout.addWidget( QtGui.QLabel( "Wait for X seconds:" ), 13, 1 )
1143        layout.addWidget( tilesCountLineEdit, 14, 0 )
1144        layout.addWidget( waitForLineEdit, 14, 1 )
1145        layout.addWidget( startMapSelectorButton, 15, 0 )
1146        layout.setRowStretch( 15, 1 )
1147
1148        self.setLayout( layout )
1149       
1150       
1151    def readSettings( self ):
1152       
1153        #global maxTilesSupported
1154       
1155        settings = QtCore.QSettings()
1156       
1157        settings.beginGroup( "fetch" )
1158       
1159        self.path2TilesDir  = settings.value( "path2TilesDir", "" ).toString()
1160        self.mapServer      = settings.value( "mapServer", "Osmarender" ).toString()
1161        self.startZoomLevel = settings.value( "startZoomLevel", 6 ).toInt()
1162        if type( self.startZoomLevel ) is not int:
1163            self.startZoomLevel = self.startZoomLevel[0]
1164           
1165        self.endZoomLevel   = settings.value( "endZoomLevel", 17 ).toInt()
1166        if type( self.endZoomLevel ) is not int:
1167            self.endZoomLevel = self.endZoomLevel[0]
1168       
1169        self.boundingBox    = settings.value( "boundingBox", "radius://22.3:48.25:9.55" ).toString()
1170        self.updateTiles    = settings.value( "updateTiles", False ).toBool()
1171        self.tilesCount     = settings.value( "tilesCount", "100" ).toString()
1172        self.waitFor        = settings.value( "waitFor", "5" ).toString()
1173        self.maxTiles       = settings.value( "maxTiles", str( maxTilesSupported ) ).toString()
1174       
1175        settings.endGroup()
1176
1177   
1178    def writeSettings( self ):
1179       
1180        settings = QtCore.QSettings()
1181       
1182        settings.beginGroup( "fetch" )
1183       
1184        settings.setValue( "path2TilesDir",    self.path2TilesDir )
1185        settings.setValue( "mapServer",        self.mapServer )     
1186        settings.setValue( "startZoomLevel",   self.startZoomLevel )
1187        settings.setValue( "endZoomLevel",     self.endZoomLevel ) 
1188        settings.setValue( "boundingBox",      self.boundingBox )   
1189        settings.setValue( "updateTiles",      self.updateTiles )   
1190        settings.setValue( "tilesCount",       self.tilesCount )   
1191        settings.setValue( "waitFor",          self.waitFor )       
1192        settings.setValue( "maxTiles",         self.maxTiles )     
1193       
1194        settings.endGroup()
1195       
1196   
1197    def startMapSelectorButtonClicked( self ):
1198       
1199        mapSelector = MapSelectorWidget()
1200       
1201        result = mapSelector.exec_()
1202       
1203        if result == 1:
1204            QtGui.QMessageBox.information( self,
1205                                           "Info",
1206                                           "Accepted" )
1207           
1208        else:
1209            QtGui.QMessageBox.information( self,
1210                                           "Info",
1211                                           "Rejected" )
1212       
1213       
1214    def waitForLineEditChanged( self, text ):
1215       
1216        self.waitFor = text
1217       
1218        self.writeSettings()
1219       
1220   
1221    def tilesCountLineEditChanged( self, text ):
1222       
1223        self.tilesCount = text
1224       
1225        self.writeSettings()
1226       
1227   
1228    def updateTilesCheckBoxStateChanged( self, state ):
1229       
1230        if state == QtCore.Qt.Unchecked:
1231            self.updateTiles = False
1232           
1233        elif state == QtCore.Qt.Checked:
1234            self.updateTiles = True
1235           
1236        else:
1237            self.updateTiles = False
1238       
1239        self.writeSettings()
1240       
1241
1242    def maxServerComboBoxActivated( self, text ):
1243       
1244        self.mapServer = text
1245        self.endZoomLevel = maxZoomLevels[ mapServerNames[ str( text ) ] ]
1246        self.endZoomLevelSpinBox.setValue( self.endZoomLevel )
1247       
1248        self.writeSettings()
1249       
1250
1251    def boundingBoxLineEditChanged( self, text ):
1252       
1253        self.boundingBox = text
1254       
1255        self.writeSettings()
1256       
1257   
1258    def path2TilesDirChanged( self, text ):
1259       
1260        self.path2TilesDir = text
1261       
1262        self.writeSettings()
1263       
1264       
1265    def path2MapDBDirChanged( self, text ):
1266       
1267        self.path2MapDBDir = text
1268       
1269        self.writeSettings()
1270       
1271
1272    def startZoomLevelChanged( self, value ):
1273       
1274        self.startZoomLevel = value
1275       
1276        self.writeSettings()
1277       
1278
1279    def endZoomLevelChanged( self, value ):
1280       
1281        self.endZoomLevel = value
1282       
1283        self.writeSettings()
1284       
1285
1286    def maxTilesLineEditChanged( self, text ):
1287       
1288        self.maxTiles = text
1289       
1290        self.writeSettings()
1291       
1292   
1293class GeneratePage( QtGui.QWidget ):       
1294
1295    def __init__( self, parent = None ):
1296       
1297        super( GeneratePage, self ).__init__( parent )
1298
1299        self.path2TilesDir  = None
1300        self.path2MapDBDir  = None
1301        self.startZoomLevel = None
1302        self.endZoomLevel   = None
1303        self.boundingBox    = None
1304        self.maxTiles       = None
1305
1306        self.readSettings()
1307       
1308        #
1309        # Validators
1310        #
1311
1312        maxTilesValidator = QtGui.QIntValidator( 1, 65535, self )
1313
1314        startZoomLevelSpinBox = QtGui.QSpinBox()
1315        startZoomLevelSpinBox.setValue( self.startZoomLevel )
1316        startZoomLevelSpinBox.setRange( 6, 17 )
1317        startZoomLevelSpinBox.valueChanged.connect( self.startZoomLevelChanged )
1318       
1319        endZoomLevelSpinBox  = QtGui.QSpinBox()
1320        endZoomLevelSpinBox.setValue( self.endZoomLevel )
1321        endZoomLevelSpinBox.setRange( 6, 17 )
1322        endZoomLevelSpinBox.valueChanged.connect( self.endZoomLevelChanged )
1323       
1324        boundingBoxLineEdit = QtGui.QLineEdit()
1325        boundingBoxLineEdit.setText( self.boundingBox )
1326        boundingBoxLineEdit.textChanged.connect( self.boundingBoxLineEditChanged )
1327
1328        maxTilesLineEdit = QtGui.QLineEdit()
1329        maxTilesLineEdit.setText( self.maxTiles )
1330        maxTilesLineEdit.setValidator( maxTilesValidator )
1331        maxTilesLineEdit.textChanged.connect( self.maxTilesLineEditChanged )
1332       
1333        path2TilesDirWidget = GetDirNameWidget( "Browse to tiles directory:", self.path2TilesDir )
1334        path2TilesDirWidget.path2DirChanged.connect( self.path2TilesDirChanged )
1335       
1336        path2MapDBDirWidget = GetDirNameWidget( "Browse to map DB directory:", self.path2MapDBDir )
1337        path2MapDBDirWidget.path2DirChanged.connect( self.path2MapDBDirChanged )
1338       
1339        layout = QtGui.QGridLayout()
1340        layout.addWidget( QtGui.QLabel( "Tiles Directory:" ), 0, 0 )
1341        layout.addWidget( path2TilesDirWidget, 1, 0, 1, 2 )
1342        layout.addWidget( QtGui.QLabel( "Map DB Directory:" ), 2, 0 )
1343        layout.addWidget( path2MapDBDirWidget, 3, 0, 1, 2 )
1344        layout.addWidget( QtGui.QLabel( "Start zoom level:" ), 4, 0 )
1345        layout.addWidget( startZoomLevelSpinBox, 5, 0, 1, 2 )
1346        layout.addWidget( QtGui.QLabel( "End zoom level:" ), 6, 0 )
1347        layout.addWidget( endZoomLevelSpinBox, 7, 0, 1, 2 )
1348        layout.addWidget( QtGui.QLabel( "Bounding box:" ), 8, 0 )
1349        layout.addWidget( boundingBoxLineEdit, 9, 0, 1, 2 )
1350        layout.addWidget( QtGui.QLabel( "Max. tiles:" ), 10, 0 )
1351        layout.addWidget( maxTilesLineEdit, 11, 0, 1, 2 )
1352        layout.addWidget( QtGui.QLabel( "" ), 12, 0 )
1353        layout.setRowStretch( 12, 1 )
1354
1355        self.setLayout( layout )
1356       
1357
1358    def readSettings( self ):
1359       
1360        settings = QtCore.QSettings()
1361       
1362        settings.beginGroup( "generate" )
1363       
1364        self.path2TilesDir  = settings.value( "path2TilesDir", "" ).toString()
1365        self.path2MapDBDir  = settings.value( "path2MapDBDir", "" ).toString()
1366        self.startZoomLevel = settings.value( "startZoomLevel", 6 ).toInt()
1367        if type( self.startZoomLevel ) is not int:
1368            self.startZoomLevel = self.startZoomLevel[0]
1369           
1370        self.endZoomLevel   = settings.value( "endZoomLevel", 17 ).toInt()
1371        if type( self.endZoomLevel ) is not int:
1372            self.endZoomLevel = self.endZoomLevel[0]
1373       
1374        self.boundingBox    = settings.value( "boundingBox", "-85.0511:-180.0:85.0511:180.0" ).toString()
1375        self.maxTiles       = settings.value( "maxTiles", str( maxTilesSupported ) ).toString()
1376       
1377        settings.endGroup()
1378
1379   
1380    def writeSettings( self ):
1381       
1382        settings = QtCore.QSettings()
1383       
1384        settings.beginGroup( "generate" )
1385       
1386        settings.setValue( "path2TilesDir",    self.path2TilesDir )
1387        settings.setValue( "path2MapDBDir",    self.path2MapDBDir )     
1388        settings.setValue( "startZoomLevel",   self.startZoomLevel )
1389        settings.setValue( "endZoomLevel",     self.endZoomLevel ) 
1390        settings.setValue( "boundingBox",      self.boundingBox )   
1391        settings.setValue( "maxTiles",         self.maxTiles )     
1392       
1393        settings.endGroup()
1394       
1395   
1396    def boundingBoxLineEditChanged( self, text ):
1397       
1398        self.boundingBox = text
1399       
1400        self.writeSettings()
1401       
1402   
1403    def path2TilesDirChanged( self, text ):
1404       
1405        self.path2TilesDir = text
1406       
1407        self.writeSettings()
1408       
1409       
1410    def path2MapDBDirChanged( self, text ):
1411       
1412        self.path2MapDBDir = text
1413       
1414        self.writeSettings()
1415       
1416
1417    def startZoomLevelChanged( self, value ):
1418       
1419        self.startZoomLevel = value
1420       
1421        self.writeSettings()
1422       
1423
1424    def endZoomLevelChanged( self, value ):
1425       
1426        self.endZoomLevel = value
1427       
1428        self.writeSettings()
1429       
1430
1431    def maxTilesLineEditChanged( self, text ):
1432       
1433        self.maxTiles = text
1434       
1435        self.writeSettings()
1436       
1437       
1438class OptionsWidget( QtGui.QDialog ):
1439
1440    def __init__( self, parent = None ):
1441
1442        super( OptionsWidget, self ).__init__( parent )
1443
1444        self.setWindowTitle( " GCLiveMapGen Options" )
1445        self.setWindowIcon( QtGui.QIcon( "icons/GC.ico" ) )
1446       
1447        self.resize( 500, 100 )
1448        self.center()
1449       
1450        self.path2LogDir        = path2LogDir
1451        self.isLoggingEnabled   = isLoggingEnabled
1452
1453        path2LogDirWidget = GetDirNameWidget( "Browse to log directory:", self.path2LogDir )
1454        path2LogDirWidget.path2DirChanged.connect( self.path2LogDirChanged )
1455       
1456        isLoggingEnabledCheckBox = QtGui.QCheckBox( "Enable logging" )
1457        isLoggingEnabledCheckBox.setChecked( self.isLoggingEnabled )
1458        isLoggingEnabledCheckBox.stateChanged.connect( self.isLoggingEnabledChanged )
1459       
1460        okButton = QtGui.QPushButton( "OK" )
1461        okButton.clicked.connect( self.accept )
1462       
1463        cancelButton = QtGui.QPushButton( "Cancel" )
1464        cancelButton.clicked.connect( self.reject )
1465       
1466        hBox = QtGui.QHBoxLayout()
1467        hBox.addStretch()
1468        hBox.addWidget( okButton )
1469        hBox.addWidget( cancelButton )
1470       
1471        layout = QtGui.QGridLayout()
1472        layout.addWidget( QtGui.QLabel( "Log Directory:" ), 0, 0 )
1473        layout.addWidget( path2LogDirWidget, 1, 0, 1, 2 )
1474        layout.addWidget( isLoggingEnabledCheckBox, 2, 0, 1, 2 )
1475        layout.addLayout( hBox, 3, 0 )
1476        layout.addWidget( QtGui.QLabel( "" ), 4, 0 )
1477        layout.setRowStretch( 4, 1 )
1478       
1479        self.setLayout( layout )
1480       
1481       
1482    def path2LogDirChanged( self, text ):
1483       
1484        self.path2LogDir = text
1485       
1486
1487    def isLoggingEnabledChanged( self, state ):
1488
1489        if state == QtCore.Qt.Checked:
1490            self.isLoggingEnabled = True
1491        else:
1492            self.isLoggingEnabled = False
1493       
1494
1495    def center( self ):
1496       
1497        screen  = QtGui.QDesktopWidget().screenGeometry()
1498        size    = self.frameSize()
1499       
1500        self.move( (screen.width() - size.width()) / 2, (screen.height() - size.height()) / 2 )
1501       
1502       
1503class MainWindow( QtGui.QMainWindow ):
1504   
1505    def __init__( self, parent = None ):
1506       
1507        super( MainWindow, self ).__init__( parent )
1508
1509        QtCore.QCoreApplication.setOrganizationName( "HD Stich" )
1510        QtCore.QCoreApplication.setOrganizationDomain( "palmtopia.de" )
1511        QtCore.QCoreApplication.setApplicationName( "GCLiveMapGen" )
1512        QtCore.QCoreApplication.setApplicationVersion( version )
1513       
1514        self.statusbar = self.statusBar()
1515
1516        self.setWindowTitle( " GCLiveMapGen GUI" )
1517        self.setWindowIcon( QtGui.QIcon( "icons/GC.ico" ) )
1518        self.resize( 500, 700 )
1519        self.center()
1520       
1521        self.statusIndicator = QtGui.QLabel( "Wait..." )
1522        self.statusbar.addPermanentWidget( self.statusIndicator, 0 )
1523       
1524        exitMenuItem = QtGui.QAction( QtGui.QIcon( "icons/Exit.png" ), "E&xit", self )
1525        exitMenuItem.setShortcut( "Ctrl+Q" )
1526        exitMenuItem.setStatusTip( "Exit application" )
1527        exitMenuItem.triggered.connect( self.close )
1528
1529        optionsMenuItem = QtGui.QAction( QtGui.QIcon( "icons/Toolbox.png" ), "&Options", self )
1530        optionsMenuItem.setShortcut( "Ctrl+O" )
1531        optionsMenuItem.setStatusTip( "Options..." )
1532        optionsMenuItem.triggered.connect( self.options )
1533       
1534        aboutMenuItem = QtGui.QAction( QtGui.QIcon( "icons/About.png" ), "&About...", self )
1535        aboutMenuItem.setStatusTip( "About this program..." )
1536        aboutMenuItem.triggered.connect( self.about )
1537       
1538        menubar = self.menuBar()
1539       
1540        fileMenu = menubar.addMenu( "&File" )
1541        fileMenu.addAction( optionsMenuItem )
1542        fileMenu.addAction( exitMenuItem )
1543       
1544        helpMenu = menubar.addMenu( "&Help" )
1545        helpMenu.addAction( aboutMenuItem )
1546       
1547        self.centralWidget = CentralWidget( self.statusIndicator )
1548        self.setCentralWidget( self.centralWidget )       
1549       
1550   
1551    def center( self ):
1552       
1553        screen  = QtGui.QDesktopWidget().screenGeometry()
1554        size    = self.frameSize()
1555       
1556        self.move( (screen.width() - size.width()) / 2, (screen.height() - size.height()) / 2 )
1557       
1558       
1559    def closeEvent( self, event ):
1560       
1561        reply = QtGui.QMessageBox.question( self,
1562                                            " Question",
1563                                            "Are you sure to quit?",
1564                                            QtGui.QMessageBox.Yes,
1565                                            QtGui.QMessageBox.No )
1566
1567        if reply == QtGui.QMessageBox.Yes:
1568            event.accept()
1569        else:
1570            event.ignore()
1571         
1572
1573    def about( self, event ):
1574       
1575        QtGui.QMessageBox.about( self,
1576                                 " About",
1577                                 "GCLiveMapGen %s\n(C) 2009 HD Stich :: hd@palmtopia.de" % (version) )
1578         
1579    def options( self, event ):
1580       
1581        #pylint: disable-msg=W0603
1582        global path2LogDir, isLoggingEnabled
1583       
1584        optionsDlg = OptionsWidget()
1585       
1586        reply = optionsDlg.exec_()
1587       
1588        if reply == QtGui.QDialog.Accepted:
1589            path2LogDir         = optionsDlg.path2LogDir
1590            isLoggingEnabled    = optionsDlg.isLoggingEnabled
1591           
1592            self.writeSettings()
1593   
1594
1595    def writeSettings( self ):
1596       
1597        settings = QtCore.QSettings()
1598       
1599        settings.beginGroup( "main" )
1600       
1601        settings.setValue( "path2LogDir",       path2LogDir )
1602        settings.setValue( "isLoggingEnabled",  isLoggingEnabled )
1603       
1604        settings.endGroup()
1605       
1606   
1607class CentralWidget( QtGui.QWidget ):
1608   
1609    def __init__( self, statusIndicator, parent = None ):
1610       
1611        super( CentralWidget, self ).__init__( parent )
1612
1613        self.currentTabIndex    = None
1614
1615        self.readSettings()
1616
1617        okButton = QtGui.QPushButton( "Start" )
1618        okButton.clicked.connect( self.okButtonClicked )
1619       
1620        quitButton = QtGui.QPushButton( "Quit" )
1621        quitButton.clicked.connect( self.quitButtonClicked )
1622
1623        self.outputWindow = OutputWidget()
1624        self.outputWindow.setReadOnly( True )
1625        self.outputWindow.setLineWrapMode( QtGui.QPlainTextEdit.NoWrap )
1626           
1627        sys.stdin   = None
1628        sys.stdout  = self.outputWindow
1629
1630        buttonBox = QtGui.QHBoxLayout()
1631        buttonBox.addStretch( 1 )
1632        buttonBox.addWidget( okButton )
1633        buttonBox.addWidget( quitButton )
1634       
1635        self.fetchPage      = FetchPage()
1636        self.generatePage   = GeneratePage()
1637        self.tilescountPage = TilesCountPage()
1638        self.autoradiusPage = AutoRadiusPage()
1639       
1640        tabBar = QtGui.QTabWidget()
1641        tabBar.addTab( self.fetchPage, "Fetch" )
1642        tabBar.addTab( self.generatePage, "Generate" )
1643        tabBar.addTab( self.tilescountPage, "Tiles Count" )
1644        tabBar.addTab( self.autoradiusPage, "Auto Radius" )
1645        tabBar.setCurrentIndex( self.currentTabIndex )
1646        tabBar.currentChanged.connect( self.tabIndexChanged )
1647       
1648        vBox = QtGui.QVBoxLayout()
1649        vBox.addWidget( tabBar )
1650        vBox.addWidget( QtGui.QLabel( "Messages:" ) )
1651        vBox.addWidget( self.outputWindow )
1652        vBox.addLayout( buttonBox )
1653       
1654        self.setLayout( vBox )
1655   
1656        self.statusIndicator = statusIndicator
1657       
1658        self.statusIndicator.setText( "Ready." )
1659       
1660
1661    def readSettings( self ):
1662       
1663        #pylint: disable-msg=W0603
1664        global path2LogDir, isLoggingEnabled
1665       
1666        settings = QtCore.QSettings()
1667       
1668        settings.beginGroup( "main" )
1669       
1670        self.currentTabIndex    = settings.value( "currentTabIndex", 0 ).toInt()
1671        if type( self.currentTabIndex ) is not int:
1672            self.currentTabIndex = self.currentTabIndex[0]
1673       
1674        path2LogDir         = settings.value( "path2LogDir", "./" ).toString()
1675        isLoggingEnabled    = settings.value( "isLoggingEnabled", 0 ).toBool()
1676           
1677        settings.endGroup()
1678
1679   
1680    def writeSettings( self ):
1681       
1682        settings = QtCore.QSettings()
1683       
1684        settings.beginGroup( "main" )
1685       
1686        settings.setValue( "currentTabIndex",          self.currentTabIndex )
1687       
1688        settings.endGroup()
1689       
1690   
1691    #
1692    # Slots
1693    #
1694   
1695    def tabIndexChanged( self, currentIndex ):
1696       
1697        self.currentTabIndex = currentIndex
1698       
1699        self.writeSettings()
1700       
1701
1702    def okButtonClicked( self ):
1703       
1704        if supportedModes[self.currentTabIndex] == "fetch":
1705           
1706            if len( self.fetchPage.path2TilesDir ) == 0:
1707                QtGui.QMessageBox.critical( self,
1708                                            " Error",
1709                                            "Please specify a path to the tiles directory!",
1710                                            QtGui.QMessageBox.Ok )
1711               
1712            else:
1713                zoomLevels = range( self.fetchPage.startZoomLevel,
1714                                    self.fetchPage.endZoomLevel + 1 )
1715
1716                self.outputWindow.clear()
1717               
1718                self.statusIndicator.setText( "Fetching tiles..." )
1719
1720                QtGui.QApplication.setOverrideCursor( QtGui.QCursor( QtCore.Qt.WaitCursor ) )
1721               
1722                try:
1723                    fetchOSMTiles( str( self.fetchPage.path2TilesDir ),
1724                                   mapServerNames[ str( self.fetchPage.mapServer ) ],
1725                                   str( self.fetchPage.boundingBox ),
1726                                   zoomLevels,
1727                                   self.fetchPage.updateTiles,
1728                                   str( self.fetchPage.tilesCount ) + ":" + str( self.fetchPage.waitFor ),
1729                                   int( self.fetchPage.maxTiles ) )
1730               
1731                finally:
1732                    QtGui.QApplication.restoreOverrideCursor()
1733                   
1734                    self.statusIndicator.setText( "Ready." )
1735
1736               
1737           
1738        if supportedModes[self.currentTabIndex] == "generate":
1739           
1740            if len( self.generatePage.path2TilesDir ) == 0:
1741                QtGui.QMessageBox.critical( self,
1742                                            " Error",
1743                                            "Please specify a path to the tiles directory!",
1744                                            QtGui.QMessageBox.Ok )
1745               
1746            elif len( self.generatePage.path2MapDBDir ) == 0:
1747                QtGui.QMessageBox.critical( self,
1748                                            " Error",
1749                                            "Please specify a path to the map DB directory!",
1750                                            QtGui.QMessageBox.Ok )
1751               
1752            else:
1753
1754                if os.path.exists( self.generatePage.path2MapDBDir ):
1755                    reply = QtGui.QMessageBox.question( self,
1756                                                        " Question",
1757                                                        "Existing map database will be erased!\nAre you sure?",
1758                                                        QtGui.QMessageBox.Yes | QtGui.QMessageBox.Cancel )
1759
1760                    if reply == QtGui.QMessageBox.Cancel:
1761                        return
1762
1763                zoomLevels = range( self.generatePage.startZoomLevel,
1764                                    self.generatePage.endZoomLevel + 1 )
1765
1766                self.outputWindow.clear()
1767               
1768                self.statusIndicator.setText( "Generating..." )
1769               
1770                QtGui.QApplication.setOverrideCursor( QtGui.QCursor( QtCore.Qt.WaitCursor ) )
1771               
1772                try:
1773                    generateMapDB( str( self.generatePage.path2TilesDir ),
1774                                   zoomLevels,
1775                                   str( self.generatePage.path2MapDBDir ),
1776                                   str( self.generatePage.boundingBox ),
1777                                   int( self.generatePage.maxTiles ) )
1778
1779                finally:
1780                    QtGui.QApplication.restoreOverrideCursor()
1781                   
1782                    self.statusIndicator.setText( "Ready." )
1783               
1784           
1785        if supportedModes[self.currentTabIndex] == "tiles-count":
1786           
1787            if len( self.tilescountPage.boundingBox ) == 0:
1788                QtGui.QMessageBox.critical( self,
1789                                            " Error",
1790                                            "Please specify a bounding box!",
1791                                            QtGui.QMessageBox.Ok )
1792               
1793            else:
1794                zoomLevels = range( self.tilescountPage.startZoomLevel,
1795                                    self.tilescountPage.endZoomLevel + 1 )
1796               
1797                self.statusIndicator.setText( "Counting tiles..." )
1798               
1799                QtGui.QApplication.setOverrideCursor( QtGui.QCursor( QtCore.Qt.WaitCursor ) )
1800               
1801                try:
1802                    tilesCount( str( self.tilescountPage.boundingBox ), zoomLevels )
1803               
1804                except ValueError:
1805                    print "WARNING: Oops, bounting box too big!"
1806               
1807                finally:
1808                    QtGui.QApplication.restoreOverrideCursor()
1809                   
1810                    self.statusIndicator.setText( "Ready." )
1811               
1812           
1813        if supportedModes[self.currentTabIndex] == "auto-radius":
1814           
1815            if (len( self.autoradiusPage.latitude ) == 0) or (len( self.autoradiusPage.longitude) == 0):
1816                QtGui.QMessageBox.critical( self,
1817                                            " Error",
1818                                            "Please specify latitude and longitude!",
1819                                            QtGui.QMessageBox.Ok )
1820            else:
1821                coord = self.autoradiusPage.latitude + ":" + self.autoradiusPage.longitude
1822               
1823                zoomLevels = range( self.autoradiusPage.startZoomLevel, self.autoradiusPage.endZoomLevel + 1 )
1824               
1825                self.statusIndicator.setText( "Calculating auto radius..." )
1826               
1827                QtGui.QApplication.setOverrideCursor( QtGui.QCursor( QtCore.Qt.WaitCursor ) )
1828               
1829                try:
1830                    autoRadius( coord, zoomLevels, int( self.autoradiusPage.maxTiles ) )
1831               
1832                finally:
1833                    QtGui.QApplication.restoreOverrideCursor()
1834                   
1835                    self.statusIndicator.setText( "Ready." )
1836               
1837
1838    def quitButtonClicked( self ):
1839       
1840        reply = QtGui.QMessageBox.question( self,
1841                                            " Question",
1842                                            "Are you sure to quit?",
1843                                            QtGui.QMessageBox.Yes,
1844                                            QtGui.QMessageBox.No )
1845
1846        if reply == QtGui.QMessageBox.Yes:
1847            sys.exit( 0 )
1848
1849
1850def runGUI():
1851
1852    app = QtGui.QApplication( sys.argv )
1853   
1854    mainWindow = MainWindow()
1855    mainWindow.show()
1856
1857    app.exec_()
1858
1859
1860def main():
1861
1862    #pylint: disable-msg=W0603
1863    global verbosity
1864
1865    usage = """
1866
1867%prog Mode Param1 ... ParamN [options]
1868
1869Modes and Params:
1870
1871%prog fetch <OSM tiles directory> <OSM Map Tile Server> <Bounding Box>
1872   
1873 - Fetch map tiles from the following OSM Map Tile Servers:
1874    'Mapnik'     - http://www.openstreetmap.org/
1875    'Osmarender' - http://www.openstreetmap.org/
1876    'CycleMap'   - http://www.opencyclemap.org/
1877    'OSMCTopo'   - http://osmc.broadbox.de/
1878     
1879   Example:
1880       
1881    %prog fetch OSM_Tiles Osmarender 48.25:9.5:48.75:10.5
1882
1883
1884%prog generate <OSM tiles directory> <GC Live Map directory>
1885   
1886 - Generates the GC Live Map Database.
1887     
1888   Example:
1889       
1890    %prog generate OSM_Tiles GCLiveMapDB
1891
1892
1893%prog tiles-count <Bounding Box>
1894
1895 - Estimate the tiles count if fetching the given area.
1896 
1897   Example:
1898   
1899    %prog tiles-count 48.25:9.5:48.75:10.5
1900
1901
1902%prog auto-radius <Coordinate>
1903
1904 - Estimate the max. supported radius (in km) for the given coordinate.
1905 
1906   Example:
1907   
1908    %prog auto-radius 48.25:9.55
1909   
1910   
1911%prog gui
1912
1913 - Start the program in GUI mode.
1914 
1915   Example:
1916   
1917    %prog gui
1918"""
1919
1920    versionInfo = "%prog " + version
1921       
1922    parser = optparse.OptionParser( usage = usage, version = versionInfo )
1923   
1924    parser.add_option( "-b", "--bounding-box", dest = "boundingBox",
1925                       help = "Generate only: Bounding box with lower left and upper right coords LAT1:LON1:LAT2:LON2.", metavar = "LAT1:LON1:LAT2:LON2" )
1926   
1927    parser.add_option( "-s", "--start-zoom", dest = "startZoom", default = 6,
1928                       help = "Start with zoom level ZOOM [Default = %default].", metavar = "ZOOM" )
1929   
1930    parser.add_option( "-e", "--end-zoom", dest = "endZoom", default = 17,
1931                       help = "End with zoom level ZOOM [Default = %default].", metavar = "ZOOM" )
1932   
1933    parser.add_option( "-u", "--update-tiles", dest = "updateTiles", default = False,
1934                       action = "store_true", help = "Fetch only: Update already existing tiles [Default = %default]." )
1935   
1936    parser.add_option( "-p", "--pausing", dest = "pausing", default = "100:5",
1937                       help = "After fetching COUNT tiles pause for TIME seconds [Default = %default].", metavar = "COUNT:TIME" )
1938   
1939    parser.add_option( "-v", "--verbosity", dest = "verbosity", default = 1,
1940                       action = "count", help = "Set verbosity level [Default = %default].")
1941   
1942    parser.add_option( "-m", "--max-tiles", dest = "maxTiles", default = maxTilesSupported,
1943                       help = "Generate only: Add MAXTILES to Map Database [Default = %default].", metavar = "MAXTILES" )
1944   
1945    parser.add_option( "-q", "--quiet", dest = "quietMode", default = False,
1946                       action = "store_true", help = "Disables all output from the script except errors and warnings." )
1947   
1948    (options, args) = parser.parse_args()
1949   
1950    if len( args ) < 1:
1951        parser.error( "Incorrect number of arguments!" )
1952   
1953    mode = args[0].lower()
1954   
1955    if mode not in supportedModes:
1956        parser.error( "Unknown mode '%s'!"  % (mode) )
1957   
1958    if mode == "fetch":
1959        if len( args ) < 4:
1960            parser.error( "Incorrect number of arguments!" )
1961   
1962        tilesDir        = args[1]
1963        osmMapServer    = args[2].lower()
1964        boundingBox     = args[3]
1965       
1966        if osmMapServer not in mapServersURLs.keys():
1967            parser.error( "Unknow OSM Map Tile Server '%s'!" % (osmMapServer) )
1968       
1969    if mode == "generate":
1970        if len( args ) < 3:
1971            parser.error( "Incorrect number of arguments!" )
1972   
1973        tilesDir    = args[1]
1974        mapDBDir    = args[2]
1975       
1976        if os.path.isdir( tilesDir ) == False:
1977            parser.error( "OSM Tiles Directory '%s' doesn't exist!" % (tilesDir) )
1978       
1979    if mode == "tiles-count":
1980        if len( args ) < 2:
1981            parser.error( "Incorrect number of arguments!" )
1982   
1983        boundingBox = args[1]
1984       
1985    if mode == "auto-radius":
1986        if len( args ) < 2:
1987            parser.error( "Incorrect number of arguments!" )
1988   
1989        centerCoord = args[1]
1990       
1991    startZoom   = int( options.startZoom )
1992    endZoom     = int( options.endZoom )
1993   
1994    if (mode == "fetch") and (endZoom > maxZoomLevels[osmMapServer] ):
1995        print "WARNING: End zoom level %d not supported by OSM map server, setting it to supported level %d." % \
1996              (endZoom, maxZoomLevels[osmMapServer])
1997        endZoom = maxZoomLevels[osmMapServer]
1998   
1999    updateTiles = int( options.updateTiles )
2000    pausing     = options.pausing
2001    verbosity   = int( options.verbosity )
2002    maxTiles    = int( options.maxTiles )
2003    quietMode   = int( options.quietMode )
2004   
2005    if quietMode == True:
2006        verbosity = 0
2007   
2008    if maxTiles > maxTilesSupported:
2009        print "WARNING: Max. tiles given (%d) is greater than max. tiles supported by GC Live (%d), option is ignored!" % \
2010              (maxTiles, maxTilesSupported)
2011   
2012    if startZoom not in range( 6, 18 ):
2013        parser.error( "Starting zoom level '%d' out of range (6 - 17)!" % (startZoom) )
2014   
2015    if endZoom not in range( 6, 18 ):
2016        parser.error( "Ending zoom level '%d' out of range (6 - 17)!" % (endZoom) )
2017   
2018    if startZoom > endZoom:
2019        parser.error( "Starting zoom level '%d' must be smaller or equal the ending zoom level '%d'!" % (startZoom, endZoom) )
2020   
2021    zoomLevels = range( startZoom, endZoom + 1 )
2022   
2023    if mode == "generate":
2024        boundingBox = options.boundingBox
2025   
2026    if (mode == "generate") and (boundingBox == None):
2027        boundingBox =  "-85.0511:-180.0:85.0511:180.0"
2028       
2029    if mode == "fetch":
2030        fetchOSMTiles( tilesDir, osmMapServer, boundingBox, zoomLevels, updateTiles, pausing, maxTiles )
2031   
2032    elif mode == "generate":
2033        generateMapDB( tilesDir, zoomLevels, mapDBDir, boundingBox, maxTiles )
2034   
2035    elif mode == "tiles-count":
2036        tilesCount( boundingBox, zoomLevels )
2037   
2038    elif mode == "auto-radius":
2039        autoRadius( centerCoord, zoomLevels, maxTiles )
2040       
2041    elif mode == "gui":
2042        runGUI()
2043   
2044
2045if __name__ == "__main__":
2046    try:
2047        main()
2048       
2049    except KeyboardInterrupt:
2050        print "WARNING: Got keyboard interrupt, exiting..."
2051   
2052#
2053# EOF
2054#
Note: See TracBrowser for help on using the repository browser.