utils.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. #
  2. # AUTHOR(S): Caitlin Haedrich <caitlin DOT haedrich AT gmail>
  3. #
  4. # PURPOSE: This module contains utility functions for InteractiveMap.
  5. #
  6. # COPYRIGHT: (C) 2021-2022 Caitlin Haedrich, and by the GRASS Development Team
  7. #
  8. # This program is free software under the GNU General Public
  9. # License (>=v2). Read the file COPYING that comes with GRASS
  10. # for details.
  11. """Utility functions warpping existing processes in a suitable way"""
  12. import os
  13. import grass.script as gs
  14. def get_region(env=None):
  15. """Returns current computational region as dictionary.
  16. Additionally, it adds long key names.
  17. """
  18. region = gs.region(env=env)
  19. region["east"] = region["e"]
  20. region["west"] = region["w"]
  21. region["north"] = region["n"]
  22. region["south"] = region["s"]
  23. return region
  24. def get_location_proj_string(env=None):
  25. """Returns projection of environment in PROJ.4 format"""
  26. out = gs.read_command("g.proj", flags="jf", env=env)
  27. return out.strip()
  28. def reproject_region(region, from_proj, to_proj):
  29. """Reproject boundary of region from one projection to another.
  30. :param dict region: region to reproject as a dictionary with long key names
  31. output of get_region
  32. :param str from_proj: PROJ.4 string of region; output of get_location_proj_string
  33. :param str in_proj: PROJ.4 string of target location;
  34. output of get_location_proj_string
  35. :return dict region: reprojected region as a dictionary with long key names
  36. """
  37. region = region.copy()
  38. proj_input = (
  39. f"{region['east']} {region['north']}\n{region['west']} {region['south']}"
  40. )
  41. proc = gs.start_command(
  42. "m.proj",
  43. input="-",
  44. separator=" , ",
  45. proj_in=from_proj,
  46. proj_out=to_proj,
  47. flags="d",
  48. stdin=gs.PIPE,
  49. stdout=gs.PIPE,
  50. stderr=gs.PIPE,
  51. )
  52. proc.stdin.write(gs.encode(proj_input))
  53. proc.stdin.close()
  54. proc.stdin = None
  55. proj_output, stderr = proc.communicate()
  56. if proc.returncode:
  57. raise RuntimeError("reprojecting region: m.proj error: " + stderr)
  58. enws = gs.decode(proj_output).split(os.linesep)
  59. elon, nlat, unused = enws[0].split(" ")
  60. wlon, slat, unused = enws[1].split(" ")
  61. region["east"] = elon
  62. region["north"] = nlat
  63. region["west"] = wlon
  64. region["south"] = slat
  65. return region
  66. def estimate_resolution(raster, mapset, location, dbase, env):
  67. """Estimates resolution of reprojected raster.
  68. :param str raster: name of raster
  69. :param str mapset: mapset of raster
  70. :param str location: name of source location
  71. :param str dbase: path to source database
  72. :param dict env: target environment
  73. :return float estimate: estimated resolution of raster in destination
  74. environment
  75. """
  76. output = gs.read_command(
  77. "r.proj",
  78. flags="g",
  79. input=raster,
  80. mapset=mapset,
  81. location=location,
  82. dbase=dbase,
  83. env=env,
  84. ).strip()
  85. params = gs.parse_key_val(output, vsep=" ")
  86. output = gs.read_command("g.region", flags="ug", env=env, **params)
  87. output = gs.parse_key_val(output, val_type=float)
  88. cell_ns = (output["n"] - output["s"]) / output["rows"]
  89. cell_ew = (output["e"] - output["w"]) / output["cols"]
  90. estimate = (cell_ew + cell_ns) / 2.0
  91. return estimate
  92. def setup_location(name, path, epsg, src_env):
  93. """Setup temporary location with different projection but
  94. same computational region as source location
  95. :param str name: name of new location
  96. :param path path: path to new location's database
  97. :param str epsg: EPSG code
  98. :param dict src_env: source environment
  99. :return str rcfile: name of new locations rcfile
  100. :return dict new_env: new environment
  101. """
  102. # Create new environment
  103. rcfile, new_env = gs.create_environment(path, name, "PERMANENT")
  104. # Location and mapset
  105. gs.create_location(path, name, epsg=epsg, overwrite=True)
  106. # Reproject region
  107. region = get_region(env=src_env)
  108. from_proj = get_location_proj_string(src_env)
  109. to_proj = get_location_proj_string(env=new_env)
  110. new_region = reproject_region(region, from_proj, to_proj)
  111. # Set region to match original region extent
  112. gs.run_command(
  113. "g.region",
  114. n=new_region["north"],
  115. s=new_region["south"],
  116. e=new_region["east"],
  117. w=new_region["west"],
  118. env=new_env,
  119. )
  120. return rcfile, new_env
  121. def get_map_name_from_d_command(module, **kwargs):
  122. """Returns map name from display command.
  123. Assumes only positional parameters.
  124. When more maps are present (e.g., d.rgb), it returns only 1.
  125. Returns empty string if fails to find it.
  126. """
  127. special = {"d.his": "hue", "d.legend": "raster", "d.rgb": "red", "d.shade": "shade"}
  128. parameter = special.get(module, "map")
  129. return kwargs.get(parameter, "")