m.proj.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. #!/usr/bin/env python
  2. ############################################################################
  3. #
  4. # MODULE: m.proj
  5. # AUTHOR: M. Hamish Bowman, Dept. Marine Science, Otago Univeristy,
  6. # New Zealand
  7. # Converted to Python by Glynn Clements
  8. # PURPOSE: cs2cs reprojection frontend for a list of coordinates.
  9. # Replacement for m.proj2 from GRASS 5
  10. # COPYRIGHT: (c) 2006,2008 Hamish Bowman, and the GRASS Development Team
  11. # This program is free software under the GNU General Public
  12. # License (>=v2). Read the file COPYING that comes with GRASS
  13. # for details.
  14. #
  15. #############################################################################
  16. # notes:
  17. # - cs2cs expects "x y" data so be sure to send it "lon lat" not "lat lon"
  18. # - if you send cs2cs a third data column, beware it might be treated as "z"
  19. # todo:
  20. # - `cut` away x,y columns into a temp file, feed to cs2cs, then `paste`
  21. # back to input file. see method in v.in.garmin.sh. that way additional
  22. # numeric and string columns would survive the trip, and 3rd column would
  23. # not be modified as z.
  24. #%Module
  25. #% description: Converts coordinates from one projection to another (cs2cs frontend).
  26. #% keywords: miscellaneous, projection
  27. #%End
  28. #%option
  29. #% key: input
  30. #% type: string
  31. #% gisprompt: old_file,file,file
  32. #% description: Input coordinate file ('-' to read from stdin)
  33. #% required : yes
  34. #% key_desc : filename
  35. #%end
  36. #%option
  37. #% key: output
  38. #% type: string
  39. #% gisprompt: new_file,file,file
  40. #% description: Output coordinate file (omit to send to stdout)
  41. #% required : no
  42. #% key_desc : filename
  43. #%end
  44. #%option
  45. #% key: fs
  46. #% type: string
  47. #% description: Field separator (format: input,output)
  48. #% required : no
  49. #% key_desc : character,character
  50. #% answer : |,|
  51. #%end
  52. #%option
  53. #% key: proj_in
  54. #% type: string
  55. #% description: Input projection parameters (PROJ.4 style)
  56. #% required : no
  57. #%end
  58. #%option
  59. #% key: proj_out
  60. #% type: string
  61. #% description: Output projection parameters (PROJ.4 style)
  62. #% required : no
  63. #%end
  64. #%flag
  65. #% key: i
  66. #% description: Use LL WGS84 as input and current location as output projection
  67. #%end
  68. #%flag
  69. #% key: o
  70. #% description: Use current location as input and LL WGS84 as output projection
  71. #%end
  72. #%flag
  73. #% key: d
  74. #% description: Output long/lat in decimal degrees or other projections with many decimal places
  75. #%end
  76. #% key: e
  77. #% description: Include input coordinates in output file
  78. #%end
  79. import sys
  80. import os
  81. import grass
  82. def main():
  83. input = options['input']
  84. output = options['output']
  85. fs = options['fs']
  86. proj_in = options['proj_in']
  87. proj_out = options['proj_out']
  88. ll_in = flags['i']
  89. ll_out = flags['o']
  90. decimal = flags['d']
  91. copy_input = flags['e']
  92. #### check for cs2cs
  93. if not grass.find_program('cs2cs'):
  94. grass.fatal("cs2cs program not found, install PROJ.4 first: http://proj.maptools.org")
  95. #### check for overenthusiasm
  96. if proj_in and ll_in:
  97. grass.fatal("Choose only one input parameter method")
  98. if proj_out and ll_out:
  99. grass.fatal("Choose only one output parameter method")
  100. if ll_in and ll_out:
  101. grass.fatal("Choise only one auto-projection parameter method")
  102. if output and not grass.overwrite() and os.path.exists(output):
  103. grass.fatal("Output file already exists")
  104. #### parse field separator
  105. ifs, ofs = fs.split(',')
  106. if ifs.lower() in ["space", "tab"]:
  107. ifs = ' '
  108. else:
  109. ifs = ifs[0]
  110. if ofs.lower() == "space":
  111. ofs = ' '
  112. elif ofs.lower() == "tab":
  113. ofs = '\t'
  114. else:
  115. ofs = ofs[0]
  116. #### set up projection params
  117. s = grass.read_command("g.proj", flags='j')
  118. kv = grass.parse_key_val(s)
  119. if "XY location" in kv['+proj'] and (ll_in or ll_out):
  120. grass.fatal("Unable to project to or from a XY location")
  121. in_proj = None
  122. if ll_in:
  123. in_proj = "+proj=longlat +datum=WGS84"
  124. grass.verbose("Assuming LL WGS84 as input, current projection as output ")
  125. if ll_out:
  126. in_proj = grass.read_command('g.proj', flags = 'jf')
  127. if proj_in:
  128. in_proj = proj_in
  129. if not in_proj:
  130. grass.fatal("Missing input projection parameters ")
  131. in_proj = in_proj.strip()
  132. grass.verbose("Input parameters: '%s'" % in_proj)
  133. out_proj = None
  134. if ll_out:
  135. out_proj = "+proj=longlat +datum=WGS84"
  136. grass.verbose("Assuming current projection as input, LL WGS84 as output ")
  137. if ll_in:
  138. out_proj = grass.read_command('g.proj', flags = 'jf')
  139. if proj_out:
  140. out_proj = proj_out
  141. if not out_proj:
  142. grass.fatal("Missing output projection parameters ")
  143. out_proj = out_proj.strip()
  144. grass.verbose("Output parameters: '%s'" % out_proj)
  145. #### set up input file
  146. if input == '-':
  147. infile = None
  148. inf = sys.stdin
  149. else:
  150. infile = input
  151. if not os.path.exists(infile):
  152. grass.fatal("Unable to read input data")
  153. inf = file(infile)
  154. grass.debug("input file=[%s]" % infile)
  155. #### set up output file
  156. if not output:
  157. outfile = None
  158. outf = sys.stdout
  159. else:
  160. outfile = output
  161. outf = open(outfile, 'w')
  162. grass.debug("output file=[%s]" % outfile)
  163. #### set up output style
  164. if not decimal:
  165. outfmt = []
  166. else:
  167. outfmt = ["-f", "%.8f"]
  168. if not copy_input:
  169. copyinp = []
  170. else:
  171. copyinp = ["-E"]
  172. #### do the conversion
  173. # Convert cs2cs DMS format to GRASS DMS format:
  174. # cs2cs | sed -e 's/d/:/g' -e "s/'/:/g" -e 's/"//g'
  175. cmd = ['cs2cs'] + copyinp + outfmt + in_proj.split() + ['+to'] + out_proj.split()
  176. p = grass.Popen(cmd, stdin = grass.PIPE, stdout = grass.PIPE)
  177. while True:
  178. line = inf.readline()
  179. if not line:
  180. break
  181. line = line.replace(ifs, ' ')
  182. p.stdin.write(line)
  183. p.stdin.flush()
  184. p.stdin.close()
  185. p.stdin = None
  186. exitcode = p.wait()
  187. if exitcode != 0:
  188. grass.warning("Projection transform probably failed, please investigate")
  189. for line in p.communicate()[0].splitlines():
  190. x, yz = line.split('\t')
  191. y, z = yz.split(' ')
  192. outf.write('%s%s%s%s%s\n' % \
  193. (x.strip(), ofs, y.strip(), ofs, z.strip()))
  194. if __name__ == "__main__":
  195. options, flags = grass.parser()
  196. main()