r.grow.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #!/usr/bin/env python3
  2. #
  3. ############################################################################
  4. #
  5. # MODULE: r.grow
  6. # AUTHOR(S): Glynn Clements
  7. # PURPOSE: Fast replacement for r.grow using r.grow.distance
  8. #
  9. # COPYRIGHT: (C) 2008 by Glynn Clements
  10. #
  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. # %Module
  17. # % description: Generates a raster map layer with contiguous areas grown by one cell.
  18. # % keyword: raster
  19. # % keyword: distance
  20. # % keyword: proximity
  21. # %end
  22. # %flag
  23. # % key: m
  24. # % description: Radius is in map units rather than cells
  25. # %end
  26. # %option G_OPT_R_INPUT
  27. # %end
  28. # %option G_OPT_R_OUTPUT
  29. # %end
  30. # %option
  31. # % key: radius
  32. # % type: double
  33. # % required: no
  34. # % multiple: no
  35. # % description: Radius of buffer in raster cells
  36. # % answer: 1.01
  37. # %end
  38. # %option
  39. # % key: metric
  40. # % type: string
  41. # % required: no
  42. # % multiple: no
  43. # % options: euclidean,maximum,manhattan
  44. # % description: Metric
  45. # % answer: euclidean
  46. # %end
  47. # %option
  48. # % key: old
  49. # % type: integer
  50. # % required: no
  51. # % multiple: no
  52. # % description: Value to write for input cells which are non-NULL (-1 => NULL)
  53. # %end
  54. # %option
  55. # % key: new
  56. # % type: integer
  57. # % required: no
  58. # % multiple: no
  59. # % description: Value to write for "grown" cells
  60. # %end
  61. import os
  62. import atexit
  63. import math
  64. import grass.script as grass
  65. from grass.exceptions import CalledModuleError
  66. # what to do in case of user break:
  67. def cleanup():
  68. for map in [temp_dist, temp_val]:
  69. if map:
  70. grass.run_command("g.remove", flags="fb", quiet=True, type="rast", name=map)
  71. def main():
  72. global temp_dist, temp_val
  73. input = options["input"]
  74. radius = float(options["radius"])
  75. metric = options["metric"]
  76. old = options["old"]
  77. new = options["new"]
  78. mapunits = flags["m"]
  79. tmp = str(os.getpid())
  80. temp_dist = "r.grow.tmp.%s.dist" % tmp
  81. shrink = False
  82. if radius < 0.0:
  83. shrink = True
  84. radius = -radius
  85. if new == "" and not shrink:
  86. temp_val = "r.grow.tmp.%s.val" % tmp
  87. new = '"%s"' % temp_val
  88. else:
  89. temp_val = None
  90. if old == "":
  91. old = '"%s"' % input
  92. if not mapunits:
  93. kv = grass.region()
  94. scale = math.sqrt(float(kv["nsres"]) * float(kv["ewres"]))
  95. radius *= scale
  96. if metric == "euclidean":
  97. metric = "squared"
  98. radius = radius * radius
  99. # check if input file exists
  100. if not grass.find_file(input)["file"]:
  101. grass.fatal(_("Raster map <%s> not found") % input)
  102. # Workaround for r.mapcalc bug #3475
  103. # Mapcalc will fail if output is a fully qualified map name
  104. out_name = options["output"].split("@")
  105. if len(out_name) == 2:
  106. if out_name[1] != grass.gisenv()["MAPSET"]:
  107. grass.fatal(_("Output can be written only to the current mapset"))
  108. output = out_name[0]
  109. else:
  110. output = out_name[0]
  111. if not shrink:
  112. try:
  113. grass.run_command(
  114. "r.grow.distance",
  115. input=input,
  116. metric=metric,
  117. distance=temp_dist,
  118. value=temp_val,
  119. )
  120. except CalledModuleError:
  121. grass.fatal(_("Growing failed. Removing temporary maps."))
  122. grass.mapcalc(
  123. '$output = if(!isnull("$input"),$old,if($dist < $radius,$new,null()))',
  124. output=output,
  125. input=input,
  126. radius=radius,
  127. old=old,
  128. new=new,
  129. dist=temp_dist,
  130. )
  131. else:
  132. # shrink
  133. try:
  134. grass.run_command(
  135. "r.grow.distance",
  136. input=input,
  137. metric=metric,
  138. distance=temp_dist,
  139. value=temp_val,
  140. flags="n",
  141. )
  142. except CalledModuleError:
  143. grass.fatal(_("Shrinking failed. Removing temporary maps."))
  144. grass.mapcalc(
  145. "$output = if(isnull($dist), $old, if($dist < $radius,null(),$old))",
  146. output=output,
  147. radius=radius,
  148. old=old,
  149. dist=temp_dist,
  150. )
  151. grass.run_command("r.colors", map=output, raster=input)
  152. # write cmd history:
  153. grass.raster_history(output)
  154. if __name__ == "__main__":
  155. options, flags = grass.parser()
  156. atexit.register(cleanup)
  157. main()