r.buffer.lowmem.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. #!/usr/bin/env python3
  2. #
  3. ############################################################################
  4. #
  5. # MODULE: r.buffer.lowmem
  6. # AUTHOR(S): Glynn Clements
  7. # PURPOSE: Low-memory replacement for r.buffer using r.grow.distance
  8. #
  9. # COPYRIGHT: (C) 2008, 2010 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. # % label: Creates a raster map showing buffer zones surrounding cells that contain non-NULL category values.
  18. # % description: This is the low-memory alternative to the classic r.buffer module.
  19. # % keyword: raster
  20. # % keyword: buffer
  21. # %end
  22. # %flag
  23. # % key: z
  24. # % description: Ignore zero (0) data cells instead of NULL cells
  25. # %end
  26. # %option G_OPT_R_INPUT
  27. # %end
  28. # %option G_OPT_R_OUTPUT
  29. # %end
  30. # %option
  31. # % key: distances
  32. # % type: double
  33. # % required: yes
  34. # % multiple: yes
  35. # % description: Distance zone(s)
  36. # %end
  37. # %option G_OPT_M_UNITS
  38. # % options: meters,kilometers,feet,miles,nautmiles
  39. # % description: Units of distance
  40. # % answer: meters
  41. # %end
  42. import os
  43. import atexit
  44. import grass.script as grass
  45. from grass.script.utils import encode
  46. scales = {
  47. "meters": 1.0,
  48. "kilometers": 1000.0,
  49. "feet": 0.3048,
  50. "miles": 1609.344,
  51. "nautmiles": 1852.0,
  52. }
  53. # what to do in case of user break:
  54. def cleanup():
  55. if grass.find_file(temp_src)["file"]:
  56. grass.run_command(
  57. "g.remove", quiet=True, flags="fb", type="raster", name=temp_src
  58. )
  59. if grass.find_file(temp_dist)["file"]:
  60. grass.run_command(
  61. "g.remove", quiet=True, flags="fb", type="raster", name=temp_dist
  62. )
  63. def main():
  64. global temp_dist, temp_src
  65. input = options["input"]
  66. output = options["output"]
  67. distances = options["distances"]
  68. units = options["units"]
  69. zero = flags["z"]
  70. tmp = str(os.getpid())
  71. temp_dist = "r.buffer.tmp.%s.dist" % tmp
  72. temp_src = "r.buffer.tmp.%s.src" % tmp
  73. # check if input file exists
  74. if not grass.find_file(input)["file"]:
  75. grass.fatal(_("Raster map <%s> not found") % input)
  76. scale = scales[units]
  77. distances = distances.split(",")
  78. distances1 = [scale * float(d) for d in distances]
  79. distances2 = [d * d for d in distances1]
  80. s = grass.read_command("g.proj", flags="j")
  81. kv = grass.parse_key_val(s)
  82. if kv["+proj"] == "longlat":
  83. metric = "geodesic"
  84. else:
  85. metric = "squared"
  86. grass.run_command(
  87. "r.grow.distance", input=input, metric=metric, distance=temp_dist, flags="m"
  88. )
  89. if zero:
  90. exp = "$temp_src = if($input == 0,null(),1)"
  91. else:
  92. exp = "$temp_src = if(isnull($input),null(),1)"
  93. grass.message(_("Extracting buffers (1/2)..."))
  94. grass.mapcalc(exp, temp_src=temp_src, input=input)
  95. exp = "$output = if(!isnull($input),$input,%s)"
  96. if metric == "squared":
  97. for n, dist2 in enumerate(distances2):
  98. exp %= "if($dist <= %f,%d,%%s)" % (dist2, n + 2)
  99. else:
  100. for n, dist2 in enumerate(distances1):
  101. exp %= "if($dist <= %f,%d,%%s)" % (dist2, n + 2)
  102. exp %= "null()"
  103. grass.message(_("Extracting buffers (2/2)..."))
  104. grass.mapcalc(exp, output=output, input=temp_src, dist=temp_dist)
  105. p = grass.feed_command("r.category", map=output, separator=":", rules="-")
  106. msg = "1:distances calculated from these locations\n"
  107. p.stdin.write(encode(msg))
  108. d0 = "0"
  109. for n, d in enumerate(distances):
  110. msg = "%d:%s-%s %s\n" % (n + 2, d0, d, units)
  111. p.stdin.write(encode(msg))
  112. d0 = d
  113. p.stdin.close()
  114. p.wait()
  115. grass.run_command("r.colors", map=output, color="rainbow")
  116. # write cmd history:
  117. grass.raster_history(output)
  118. if __name__ == "__main__":
  119. options, flags = grass.parser()
  120. atexit.register(cleanup)
  121. main()