r.in.srtm.py 7.5 KB

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