r.in.srtm.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. #!/usr/bin/env python
  2. #
  3. ############################################################################
  4. #
  5. # MODULE: r_in_aster.py
  6. # AUTHOR(S): Markus Neteler 11/2003 neteler AT itc it
  7. # Hamish Bowman
  8. # Glynn Clements
  9. # PURPOSE: import of SRTM hgt files into GRASS
  10. #
  11. # COPYRIGHT: (C) 2004, 2006 by the GRASS Development Team
  12. #
  13. # This program is free software under the GNU General Public
  14. # License (>=v2). Read the file COPYING that comes with GRASS
  15. # for details.
  16. #
  17. # Dec 2004: merged with srtm_generate_hdr.sh (M. Neteler)
  18. # corrections and refinement (W. Kyngesburye)
  19. # Aug 2004: modified to accept files from other directories
  20. # (by H. Bowman)
  21. # June 2005: added flag to read in US 1-arcsec tiles (H. Bowman)
  22. # April 2006: links updated from ftp://e0dps01u.ecs.nasa.gov/srtm/
  23. # to current links below
  24. # October 2008: Converted to Python by Glynn Clements
  25. #########################
  26. # Derived from:
  27. # ftp://e0srp01u.ecs.nasa.gov/srtm/version1/Documentation/Notes_for_ARCInfo_users.txt
  28. # (note: document was updated silently end of 2003)
  29. #
  30. # ftp://e0srp01u.ecs.nasa.gov/srtm/version1/Documentation/SRTM_Topo.txt
  31. # "3.0 Data Formats
  32. # [...]
  33. # To be more exact, these coordinates refer to the geometric center of
  34. # the lower left pixel, which in the case of SRTM-1 data will be about
  35. # 30 meters in extent."
  36. #
  37. #- SRTM 90 Tiles are 1 degree by 1 degree
  38. #- SRTM filename coordinates are said to be the *center* of the LL pixel.
  39. # N51E10 -> lower left cell center
  40. #
  41. #- BIL uses *center* of the UL (!) pixel:
  42. # http://downloads.esri.com/support/whitepapers/other_/eximgav.pdf
  43. #
  44. #- GDAL uses *corners* of pixels for its coordinates.
  45. #
  46. # NOTE: Even, if small difference: SRTM is referenced to EGM96, not WGS84 ellps
  47. # http://earth-info.nga.mil/GandG/wgs84/gravitymod/egm96/intpt.html
  48. #
  49. #########################
  50. #%Module
  51. #% description: Imports SRTM HGT files into raster map.
  52. #% keyword: raster
  53. #% keyword: import
  54. #%End
  55. #%option G_OPT_F_INPUT
  56. #% description: Name of SRTM input tile (file without .hgt.zip extension)
  57. #%end
  58. #%option G_OPT_R_OUTPUT
  59. #% description: Name for output raster map (default: input tile)
  60. #% required : no
  61. #%end
  62. #%flag
  63. #% key: 1
  64. #% description: Input is a 1-arcsec tile (default: 3-arcsec)
  65. #%end
  66. tmpl1sec = """BYTEORDER M
  67. LAYOUT BIL
  68. NROWS 3601
  69. NCOLS 3601
  70. NBANDS 1
  71. NBITS 16
  72. BANDROWBYTES 7202
  73. TOTALROWBYTES 7202
  74. BANDGAPBYTES 0
  75. PIXELTYPE SIGNEDINT
  76. NODATA -32768
  77. ULXMAP %s
  78. ULYMAP %s
  79. XDIM 0.000277777777777778
  80. YDIM 0.000277777777777778
  81. """
  82. swbd1sec = """BYTEORDER M
  83. LAYOUT BIL
  84. NROWS 3601
  85. NCOLS 3601
  86. NBANDS 1
  87. NBITS 8
  88. BANDROWBYTES 7202
  89. TOTALROWBYTES 7202
  90. BANDGAPBYTES 0
  91. PIXELTYPE SIGNEDINT
  92. NODATA -32768
  93. ULXMAP %s
  94. ULYMAP %s
  95. XDIM 0.000277777777777778
  96. YDIM 0.000277777777777778
  97. """
  98. tmpl3sec = """BYTEORDER M
  99. LAYOUT BIL
  100. NROWS 1201
  101. NCOLS 1201
  102. NBANDS 1
  103. NBITS 16
  104. BANDROWBYTES 2402
  105. TOTALROWBYTES 2402
  106. BANDGAPBYTES 0
  107. PIXELTYPE SIGNEDINT
  108. NODATA -32768
  109. ULXMAP %s
  110. ULYMAP %s
  111. XDIM 0.000833333333333
  112. YDIM 0.000833333333333
  113. """
  114. proj = ''.join([
  115. 'GEOGCS[',
  116. '"wgs84",',
  117. 'DATUM["WGS_1984",SPHEROID["wgs84",6378137,298.257223563],TOWGS84[0.000000,0.000000,0.000000]],',
  118. 'PRIMEM["Greenwich",0],',
  119. 'UNIT["degree",0.0174532925199433]',
  120. ']'])
  121. import os
  122. import shutil
  123. import atexit
  124. import grass.script as grass
  125. from grass.exceptions import CalledModuleError
  126. # i18N
  127. import gettext
  128. gettext.install('grassmods', os.path.join(os.getenv("GISBASE"), 'locale'))
  129. def cleanup():
  130. if not in_temp:
  131. return
  132. for ext in ['.bil', '.hdr', '.prj', '.hgt.zip']:
  133. grass.try_remove(tile + ext)
  134. os.chdir('..')
  135. grass.try_rmdir(tmpdir)
  136. def main():
  137. global tile, tmpdir, in_temp
  138. in_temp = False
  139. # to support SRTM water body
  140. swbd = False
  141. input = options['input']
  142. output = options['output']
  143. one = flags['1']
  144. # are we in LatLong location?
  145. s = grass.read_command("g.proj", flags='j')
  146. kv = grass.parse_key_val(s)
  147. if not '+proj' in kv.keys() or kv['+proj'] != 'longlat':
  148. grass.fatal(_("This module only operates in LatLong locations"))
  149. # use these from now on:
  150. infile = input
  151. while infile[-4:].lower() in ['.hgt', '.zip', '.raw']:
  152. infile = infile[:-4]
  153. (fdir, tile) = os.path.split(infile)
  154. if not output:
  155. tileout = tile
  156. else:
  157. tileout = output
  158. if '.hgt' in input:
  159. suff = '.hgt'
  160. else:
  161. suff = '.raw'
  162. swbd = True
  163. zipfile = "{im}{su}.zip".format(im=infile, su=suff)
  164. hgtfile = "{im}{su}".format(im=infile, su=suff)
  165. if os.path.isfile(zipfile):
  166. # check if we have unzip
  167. if not grass.find_program('unzip'):
  168. grass.fatal(_('The "unzip" program is required, please install it first'))
  169. # really a ZIP file?
  170. # make it quiet in a safe way (just in case -qq isn't portable)
  171. tenv = os.environ.copy()
  172. tenv['UNZIP'] = '-qq'
  173. if grass.call(['unzip', '-t', zipfile], env=tenv) != 0:
  174. grass.fatal(_("'%s' does not appear to be a valid zip file.") % zipfile)
  175. is_zip = True
  176. elif os.path.isfile(hgtfile):
  177. # try and see if it's already unzipped
  178. is_zip = False
  179. else:
  180. grass.fatal(_("File '%s' or '%s' not found") % (zipfile, hgtfile))
  181. # make a temporary directory
  182. tmpdir = grass.tempfile()
  183. grass.try_remove(tmpdir)
  184. os.mkdir(tmpdir)
  185. if is_zip:
  186. shutil.copyfile(zipfile, os.path.join(tmpdir,
  187. "{im}{su}.zip".format(im=tile,
  188. su=suff)))
  189. else:
  190. shutil.copyfile(hgtfile, os.path.join(tmpdir,
  191. "{im}{su}".format(im=tile[:7],
  192. su=suff)))
  193. # change to temporary directory
  194. os.chdir(tmpdir)
  195. in_temp = True
  196. zipfile = "{im}{su}.zip".format(im=tile, su=suff)
  197. hgtfile = "{im}{su}".format(im=tile[:7], su=suff)
  198. bilfile = tile + ".bil"
  199. if is_zip:
  200. # unzip & rename data file:
  201. grass.message(_("Extracting '%s'...") % infile)
  202. if grass.call(['unzip', zipfile], env=tenv) != 0:
  203. grass.fatal(_("Unable to unzip file."))
  204. grass.message(_("Converting input file to BIL..."))
  205. os.rename(hgtfile, bilfile)
  206. north = tile[0]
  207. ll_latitude = int(tile[1:3])
  208. east = tile[3]
  209. ll_longitude = int(tile[4:7])
  210. # are we on the southern hemisphere? If yes, make LATITUDE negative.
  211. if north == "S":
  212. ll_latitude *= -1
  213. # are we west of Greenwich? If yes, make LONGITUDE negative.
  214. if east == "W":
  215. ll_longitude *= -1
  216. # Calculate Upper Left from Lower Left
  217. ulxmap = "%.1f" % ll_longitude
  218. # SRTM90 tile size is 1 deg:
  219. ulymap = "%.1f" % (ll_latitude + 1)
  220. if not one:
  221. tmpl = tmpl3sec
  222. elif swbd:
  223. grass.message(_("Attempting to import 1-arcsec SWBD data"))
  224. tmpl = swbd1sec
  225. else:
  226. grass.message(_("Attempting to import 1-arcsec data"))
  227. tmpl = tmpl1sec
  228. header = tmpl % (ulxmap, ulymap)
  229. hdrfile = tile + '.hdr'
  230. outf = file(hdrfile, 'w')
  231. outf.write(header)
  232. outf.close()
  233. # create prj file: To be precise, we would need EGS96! But who really cares...
  234. prjfile = tile + '.prj'
  235. outf = file(prjfile, 'w')
  236. outf.write(proj)
  237. outf.close()
  238. try:
  239. grass.run_command('r.in.gdal', input=bilfile, out=tileout)
  240. except:
  241. grass.fatal(_("Unable to import data"))
  242. # nice color table
  243. if not swbd:
  244. grass.run_command('r.colors', map=tileout, color='srtm')
  245. # write cmd history:
  246. grass.raster_history(tileout)
  247. grass.message(_("Done: generated map ") + tileout)
  248. grass.message(_("(Note: Holes in the data can be closed with 'r.fillnulls' using splines)"))
  249. if __name__ == "__main__":
  250. options, flags = grass.parser()
  251. atexit.register(cleanup)
  252. main()