region.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. #
  2. # AUTHOR(S): Anna Petrasova <kratochanna AT gmail>
  3. #
  4. # PURPOSE: This module contains functionality for managing region
  5. # during rendering.
  6. #
  7. # COPYRIGHT: (C) 2021 Anna Petrasova, and by the GRASS Development Team
  8. #
  9. # This program is free software under the GNU General Public
  10. # License (>=v2). Read the file COPYING that comes with GRASS
  11. # for details.
  12. import grass.script as gs
  13. from grass.exceptions import CalledModuleError
  14. from .utils import (
  15. get_location_proj_string,
  16. get_region,
  17. reproject_region,
  18. get_map_name_from_d_command,
  19. )
  20. class RegionManagerForInteractiveMap:
  21. def __init__(self, use_region, saved_region, src_env, tgt_env):
  22. """Manages region during rendering for interactive map.
  23. :param use_region: if True, use either current or provided saved region,
  24. else derive region from rendered layers
  25. :param saved_region: if name of saved_region is provided,
  26. this region is then used for rendering
  27. :param src_env: source environment (original projection)
  28. :param tgt_env: target environment (pseudomercator)
  29. """
  30. self._use_region = use_region
  31. self._saved_region = saved_region
  32. self._src_env = src_env
  33. self._tgt_env = tgt_env
  34. self._bbox = [[90, 180], [-90, -180]]
  35. @property
  36. def bbox(self):
  37. """Bbox property for accessing maximum
  38. bounding box of all rendered layers.
  39. """
  40. return self._bbox
  41. def set_region_from_raster(self, raster):
  42. """Sets computational region for rendering.
  43. This functions sets computational region based on
  44. a raster map in the target environment.
  45. If user specified the name of saved region during object's initialization,
  46. the provided region is used. If it's not specified
  47. and use_region=True, current region is used.
  48. Also enlarges bounding box based on the raster.
  49. """
  50. if self._saved_region:
  51. self._src_env["GRASS_REGION"] = gs.region_env(
  52. region=self._saved_region, env=self._src_env
  53. )
  54. elif self._use_region:
  55. # use current
  56. self._set_bbox(self._src_env)
  57. return
  58. else:
  59. self._src_env["GRASS_REGION"] = gs.region_env(
  60. raster=raster, env=self._src_env
  61. )
  62. region = get_region(env=self._src_env)
  63. from_proj = get_location_proj_string(self._src_env)
  64. to_proj = get_location_proj_string(env=self._tgt_env)
  65. new_region = reproject_region(region, from_proj, to_proj)
  66. gs.run_command(
  67. "g.region",
  68. n=new_region["north"],
  69. s=new_region["south"],
  70. e=new_region["east"],
  71. w=new_region["west"],
  72. env=self._tgt_env,
  73. )
  74. self._set_bbox(self._src_env)
  75. def set_bbox_vector(self, vector):
  76. """Enlarge bounding box based on vector"""
  77. env = self._src_env.copy()
  78. env["GRASS_REGION"] = gs.region_env(vector=vector, env=env)
  79. self._set_bbox(env)
  80. def _set_bbox(self, env):
  81. bbox = gs.parse_command("g.region", flags="bg", env=env)
  82. s = float(bbox["ll_s"])
  83. w = float(bbox["ll_w"])
  84. n = float(bbox["ll_n"])
  85. e = float(bbox["ll_e"])
  86. if self._bbox[0][0] > s:
  87. self._bbox[0][0] = s
  88. if self._bbox[0][1] > w:
  89. self._bbox[0][1] = w
  90. if self._bbox[1][0] < n:
  91. self._bbox[1][0] = n
  92. if self._bbox[1][1] < e:
  93. self._bbox[1][1] = e
  94. class RegionManagerFor2D:
  95. def __init__(self, use_region, saved_region, env):
  96. """Manages region during rendering.
  97. :param use_region: if True, use either current or provided saved region,
  98. else derive region from rendered layers
  99. :param saved_region: if name of saved_region is provided,
  100. this region is then used for rendering
  101. :param env: environment for rendering
  102. """
  103. self._env = env
  104. self._use_region = use_region
  105. self._saved_region = saved_region
  106. self._extent_set = False
  107. self._resolution_set = False
  108. def set_region_from_env(self, env):
  109. """Copies GRASS_REGION from provided environment
  110. to local environment to set the computational region"""
  111. if "GRASS_REGION" in env:
  112. self._env["GRASS_REGION"] = env["GRASS_REGION"]
  113. def set_region_from_command(self, module, **kwargs):
  114. """Sets computational region for rendering.
  115. This functions identifies a raster/vector map from command
  116. and tries to set computational region based on that.
  117. It takes the extent from the first layer (raster or vector)
  118. and resolution and alignment from first raster layer.
  119. If user specified the name of saved region during object's initialization,
  120. the provided region is used. If it's not specified
  121. and use_region=True, current region is used.
  122. """
  123. if self._saved_region:
  124. self._env["GRASS_REGION"] = gs.region_env(
  125. region=self._saved_region, env=self._env
  126. )
  127. return
  128. if self._use_region:
  129. # use current
  130. return
  131. if self._resolution_set and self._extent_set:
  132. return
  133. name = get_map_name_from_d_command(module, **kwargs)
  134. if not name:
  135. return
  136. if len(name.split()) > 1:
  137. name = name.split()[0]
  138. try:
  139. if module.startswith("d.vect"):
  140. if not self._resolution_set and not self._extent_set:
  141. self._env["GRASS_REGION"] = gs.region_env(
  142. vector=name, env=self._env
  143. )
  144. self._extent_set = True
  145. else:
  146. if not self._resolution_set and not self._extent_set:
  147. self._env["GRASS_REGION"] = gs.region_env(
  148. raster=name, env=self._env
  149. )
  150. self._extent_set = True
  151. self._resolution_set = True
  152. elif not self._resolution_set:
  153. self._env["GRASS_REGION"] = gs.region_env(align=name, env=self._env)
  154. self._resolution_set = True
  155. except CalledModuleError:
  156. return
  157. class RegionManagerFor3D:
  158. def __init__(self, use_region, saved_region):
  159. """Manages region during rendering.
  160. :param use_region: if True, use either current or provided saved region,
  161. else derive region from rendered layers
  162. :param saved_region: if name of saved_region is provided,
  163. this region is then used for rendering
  164. """
  165. self._use_region = use_region
  166. self._saved_region = saved_region
  167. def set_region_from_command(self, env, **kwargs):
  168. """Sets computational region for rendering.
  169. This functions identifies a raster map from m.nviz.image command
  170. and tries to set computational region based on that.
  171. If user specified the name of saved region during object's initialization,
  172. the provided region is used. If it's not specified
  173. and use_region=True, current region is used.
  174. """
  175. if self._saved_region:
  176. env["GRASS_REGION"] = gs.region_env(region=self._saved_region, env=env)
  177. return
  178. if self._use_region:
  179. # use current
  180. return
  181. if "elevation_map" in kwargs:
  182. elev = kwargs["elevation_map"].split(",")[0]
  183. try:
  184. env["GRASS_REGION"] = gs.region_env(raster=elev, env=env)
  185. except CalledModuleError:
  186. return