1 | '''
|
---|
2 | Generate igor-shaded world tiles for the (most of) the world.
|
---|
3 | Assumes you have the SRTM tiles of area of interest.
|
---|
4 |
|
---|
5 | Loads in SRTM data for the world in slices and generates hillshaded web
|
---|
6 | tiles for the data from zoom 7 to 11. Higher zooms are possible, but each
|
---|
7 | lower zoom level requires loading 4x more SRTM data into RAM.
|
---|
8 |
|
---|
9 | Another solution will need to be worked out to generate lower zooms.
|
---|
10 |
|
---|
11 | Each slice overlaps the other by 1 degree in order to prevent gaps in the tile data.
|
---|
12 |
|
---|
13 | Run with a slice number as a command line parameter and will generate a script starting at that file.
|
---|
14 | Useful to continue after a crash.
|
---|
15 |
|
---|
16 | '''
|
---|
17 | import os
|
---|
18 | import argparse
|
---|
19 | import time
|
---|
20 | from datetime import timedelta
|
---|
21 |
|
---|
22 | #defaults which can be modified via command-line params
|
---|
23 | maperitive_path = "G:\\Maperitive\\"
|
---|
24 | script_file = "gen_terrain.mscript"
|
---|
25 | tiles_dir = "G:\\Tiles"
|
---|
26 |
|
---|
27 | #These are the full bounds of the SRTMGL1 data
|
---|
28 | map_bounds = {
|
---|
29 | 'W':-180,
|
---|
30 | 'E':180,
|
---|
31 | 'S':-56,
|
---|
32 | 'N':59,
|
---|
33 | }
|
---|
34 |
|
---|
35 | script_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 |
|
---|
41 | set-dem-source name=SRTM1
|
---|
42 | '''
|
---|
43 |
|
---|
44 | script_foot = '''
|
---|
45 | '''
|
---|
46 |
|
---|
47 | script_gen = '''
|
---|
48 | //Tile {tnum} of {ttot}
|
---|
49 | clear-map
|
---|
50 | set-geo-bounds {Wb},{Sb},{Eb},{Nb}
|
---|
51 | generate-relief-igor color="black" intensity=3 sample-rate=1
|
---|
52 | //generate-contours interval=10
|
---|
53 | set-geo-bounds {W},{S},{E},{N}
|
---|
54 | generate-tiles exclude-partial=true minzoom=7 maxzoom=11 tilesdir={tdir}
|
---|
55 | '''
|
---|
56 |
|
---|
57 | def 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 |
|
---|
101 | def 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 |
|
---|
111 | def 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 |
|
---|
145 | def 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 |
|
---|
152 | if __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) |
---|