PythonScripts: gen_terrain_tiles_script.py

File gen_terrain_tiles_script.py, 5.8 KB (added by Uriel, 7 years ago)

This script can be used to generate a web tiles set of terrain shading for the entire world from zoom levels 7 and up.

Line 
1'''
2Generate igor-shaded world tiles for the (most of) the world.
3Assumes you have the SRTM tiles of area of interest.
4
5Loads in SRTM data for the world in slices and generates hillshaded web
6tiles for the data from zoom 7 to 11. Higher zooms are possible, but each
7lower zoom level requires loading 4x more SRTM data into RAM.
8
9Another solution will need to be worked out to generate lower zooms.
10
11Each slice overlaps the other by 1 degree in order to prevent gaps in the tile data.
12
13Run with a slice number as a command line parameter and will generate a script starting at that file.
14Useful to continue after a crash.
15
16'''
17import os
18import argparse
19import time
20from datetime import timedelta
21
22#defaults which can be modified via command-line params
23maperitive_path = "G:\\Maperitive\\"
24script_file = "gen_terrain.mscript"
25tiles_dir   = "G:\\Tiles"
26
27#These are the full bounds of the SRTMGL1 data
28map_bounds = {
29    'W':-180,
30    'E':180,
31    'S':-56,
32    'N':59,
33}
34
35script_head = '''
36// SCRIPT TO GENERATE WORLD TERRAIN SHADING TILES
37// Expects SRTM1 data in Maperitive\Cache\Rasters\SRTM1
38//   Which should be a symlink to \SRTMGL1_full
39// Will output tiles to {tdir}
40
41set-dem-source name=SRTM1
42'''
43
44script_foot = '''
45'''
46
47script_gen = '''
48//Tile {tnum} of {ttot}
49clear-map
50set-geo-bounds {Wb},{Sb},{Eb},{Nb}
51generate-relief-igor color="black" intensity=3 sample-rate=1
52//generate-contours interval=10
53set-geo-bounds {W},{S},{E},{N}
54generate-tiles exclude-partial=true minzoom=7 maxzoom=11 tilesdir={tdir}
55'''
56
57def gen_bounds(start=1):
58    #generate the maperitive script metadata
59    print "Generating script starting at slice", start
60
61    #Break the map into chunks using 6 degree steps.
62    #With 6 degree steps, 2 degree overlap and 1 degree bleed is required to generate zoom 7.
63    EW_step = 6 #longitude
64    NS_step = 6 #latitude
65    overlap = 2 #How much to overlap each slice of the world
66    bleed   = 1 #How much extra data to load (Should be 1)
67
68    EW_range = range(map_bounds['W'], map_bounds['E']-(EW_step-overlap)+1, (EW_step-overlap))
69    NS_range = range(map_bounds['S'], map_bounds['N']-(NS_step-overlap)+1, (NS_step-overlap))
70
71    mem = EW_step * NS_step * (3601*3601*2)
72    mem_bleed = (2*bleed + EW_step) * (2*bleed + NS_step) * (3601*3601*2)
73    total = len(EW_range) * len(NS_range)
74    print "Dividing world into {} slices ({:,} bytes each, max {:,} with bleed)".format(total,mem,mem_bleed)
75
76    metadata = []
77    num = 1
78    for EW in EW_range:
79        for NS in NS_range:
80            bounds = {
81                'tnum': num,
82                'ttot': total,
83                'W':max(map_bounds['W']+.00001, EW),
84                'E':min(map_bounds['E']-.00001, EW + EW_step),
85                'S':max(map_bounds['S']+.00001, NS),
86                'N':min(map_bounds['N']-.00001, NS + NS_step),               
87                'Wb':max(map_bounds['W'], EW-bleed),
88                'Eb':min(map_bounds['E'], EW+EW_step+bleed),
89                'Sb':max(map_bounds['S'], NS-bleed),
90                'Nb':min(map_bounds['N'], NS+NS_step+bleed),
91            }
92
93            if num == start:
94                print "Start tile: {W},{S},{E},{N}".format(**bounds)
95            if num >= start:
96                metadata.append(bounds)
97
98            num += 1
99    return metadata
100
101def gen_script(data, args):
102    # Generate the maperitive script
103    print "Writing script..."
104    print os.path.join(args.mdir, "Scripts", args.script)
105    with open(os.path.join(args.mdir, "Scripts", args.script), "w") as F:
106        F.write(script_head.format(tdir=args.tdir))
107        for elem in data:
108            F.write(script_gen.format(tdir=args.tdir, **elem))
109        F.write(script_foot)
110
111def run_script(data, args):
112    #Generate one block of the script at a time and run it
113    #If there's an error (such as out of memory) start again
114    print "Running script..."
115    t_tot = 0;
116    t_last = 0;
117    for elem in data:
118        t_start = time.time()
119        with open(os.path.join(args.mdir, "Scripts", args.script), "w") as F:
120            F.write(script_head.format(tdir=args.tdir))
121            F.write(script_gen.format(tdir=args.tdir, **elem))
122       
123        path = os.path.join(args.mdir,"Maperitive.Console.exe")
124        script = os.path.join("Scripts", args.script)
125
126        done = False
127        while not done:
128            print "*"*80
129            print ("Slice %d of %d"%(elem['tnum'], elem['ttot'])).center(80, "*")
130            t_str = "Time Elapsed: %s"%timedelta(seconds=t_tot)
131            if t_last > 0:
132                t_str += "-- Last Slice: %s"%timedelta(seconds=t_last)
133            print t_str.center(80,"*")
134            print "*"*80
135
136            err = os.system(path + " " + script)
137            print "Error:", err
138            if err == 0:
139                done = True
140        t_end = time.time()
141        t_last = t_end - t_start
142        t_tot += t_last
143
144
145def main(args):
146    data = gen_bounds(args.index)
147    if args.run:
148        run_script(data, args)
149    else:
150        gen_script(data, args)
151
152if __name__ == '__main__':
153    P = argparse.ArgumentParser(description="Generates a maperitive script to create a terrain map of the world")
154    P.add_argument("-i", "--index", type=int, default=1,
155         help="Index to start at")
156    P.add_argument("-r", "--run", action="store_true",
157        help="Add this argument to run maperitive also")
158    P.add_argument("--mdir", default=maperitive_path,
159        help="Path to the Maperitive folder to write the script to. Default: %s"%maperitive_path)
160    P.add_argument("--tdir", default=tiles_dir,
161        help="Path to output the generated tiles. Default: %s"%tiles_dir)
162    P.add_argument("--script", default=script_file,
163        help="File name of the script to generate. Default: %s"%script_file)
164    args = P.parse_args()
165
166    main(args)