r.in.srtm.py 6.5 KB

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