r.mask.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. #!/usr/bin/env python3
  2. #
  3. ############################################################################
  4. #
  5. # MODULE: r.mask
  6. # AUTHOR(S): Michael Barton, Arizona State University
  7. # Markus Neteler
  8. # Converted to Python by Glynn Clements
  9. # Markus Metz
  10. # PURPOSE: Facilitates creation of raster MASK
  11. # COPYRIGHT: (C) 2005-2013 by the GRASS Development Team
  12. #
  13. # This program is free software under the GNU General Public
  14. # License (>=v2). Read the file COPYING that comes with GRASS
  15. # for details.
  16. #
  17. #############################################################################
  18. # %module
  19. # % description: Creates a MASK for limiting raster operation.
  20. # % keyword: raster
  21. # % keyword: mask
  22. # % keyword: null data
  23. # % keyword: no-data
  24. # % overwrite: yes
  25. # %end
  26. # %option G_OPT_R_INPUT
  27. # % key: raster
  28. # % description: Name of raster map to use as mask
  29. # % required: NO
  30. # % guisection: Raster
  31. # %end
  32. # %option
  33. # % key: maskcats
  34. # % type: string
  35. # % label: Raster values to use for mask
  36. # % description: Format: 1 2 3 thru 7 *
  37. # % answer: *
  38. # % guisection: Raster
  39. # %end
  40. # %option G_OPT_V_INPUT
  41. # % key: vector
  42. # % label: Name of vector map to use as mask
  43. # % required: NO
  44. # % guisection: Vector
  45. # %end
  46. # %option G_OPT_V_FIELD
  47. # % label: Layer number or name (vector)
  48. # % required: NO
  49. # % guisection: Vector
  50. # %end
  51. # %option G_OPT_V_CATS
  52. # % label: Category values (vector)
  53. # % guisection: Vector
  54. # %end
  55. # %option G_OPT_DB_WHERE
  56. # % label: WHERE conditions of SQL statement without 'where' keyword (vector)
  57. # % guisection: Vector
  58. # %end
  59. # %flag
  60. # % key: i
  61. # % description: Create inverse mask
  62. # % guisection: Create
  63. # %end
  64. # %flag
  65. # % key: r
  66. # % description: Remove existing mask (overrides other options)
  67. # % guisection: Remove
  68. # %end
  69. import os
  70. import sys
  71. import atexit
  72. import grass.script as grass
  73. from grass.script.utils import encode
  74. from grass.exceptions import CalledModuleError
  75. def cleanup():
  76. if tmp:
  77. grass.run_command("g.remove", flags="f", type="raster", name=tmp, quiet=True)
  78. if tmp_hull:
  79. grass.run_command(
  80. "g.remove", flags="f", type="vector", name=tmp_hull, quiet=True
  81. )
  82. def main():
  83. raster = options["raster"]
  84. maskcats = options["maskcats"]
  85. vector = options["vector"]
  86. layer = options["layer"]
  87. cats = options["cats"]
  88. where = options["where"]
  89. remove = flags["r"]
  90. invert = flags["i"]
  91. if not remove and not raster and not vector:
  92. grass.fatal(_("Either parameter <raster> or parameter <vector> is required"))
  93. mapset = grass.gisenv()["MAPSET"]
  94. exists = bool(grass.find_file("MASK", element="cell", mapset=mapset)["file"])
  95. if remove:
  96. # -> remove
  97. if exists:
  98. if sys.platform == "win32":
  99. grass.run_command(
  100. "g.remove", flags="if", quiet=True, type="raster", name="MASK"
  101. )
  102. else:
  103. grass.run_command(
  104. "g.remove", flags="f", quiet=True, type="raster", name="MASK"
  105. )
  106. grass.message(_("Raster MASK removed"))
  107. else:
  108. grass.fatal(_("No existing MASK to remove"))
  109. else:
  110. # -> create
  111. if exists:
  112. if not grass.overwrite():
  113. grass.fatal(
  114. _(
  115. "MASK already found in current mapset. Delete first or overwrite."
  116. )
  117. )
  118. else:
  119. grass.warning(_("MASK already exists and will be overwritten"))
  120. grass.run_command(
  121. "g.remove", flags="f", quiet=True, type="raster", name="MASK"
  122. )
  123. if raster:
  124. # check if input raster exists
  125. if not grass.find_file(raster)["file"]:
  126. grass.fatal(_("Raster map <%s> not found") % raster)
  127. if maskcats != "*" and not remove:
  128. if grass.raster_info(raster)["datatype"] != "CELL":
  129. grass.fatal(
  130. _(
  131. "The raster map <%s> must be integer (CELL type) "
  132. " in order to use the 'maskcats' parameter"
  133. )
  134. % raster
  135. )
  136. p = grass.feed_command(
  137. "r.reclass", input=raster, output="MASK", overwrite=True, rules="-"
  138. )
  139. res = "%s = 1" % maskcats
  140. p.stdin.write(encode(res))
  141. p.stdin.close()
  142. p.wait()
  143. elif vector:
  144. vector_name = grass.find_file(vector, "vector")["fullname"]
  145. if not vector_name:
  146. grass.fatal(_("Vector map <%s> not found") % vector)
  147. # parser bug?
  148. if len(cats) == 0:
  149. cats = None
  150. if len(where) == 0:
  151. where = None
  152. if grass.vector_info_topo(vector_name)["areas"] < 1:
  153. grass.warning(
  154. _(
  155. "No area found in vector map <%s>. "
  156. "Creating a convex hull for MASK."
  157. )
  158. % vector_name
  159. )
  160. global tmp_hull
  161. tmp_hull = "tmp_hull_%d" % os.getpid()
  162. to_rast_input = tmp_hull
  163. # force 'flat' convex hull for 3D vector maps
  164. try:
  165. grass.run_command(
  166. "v.hull",
  167. flags="f",
  168. quiet=True,
  169. input=vector_name,
  170. output=tmp_hull,
  171. layer=layer,
  172. cats=cats,
  173. where=where,
  174. )
  175. except CalledModuleError:
  176. grass.fatal(
  177. _("Unable to create a convex hull for vector map <%s>")
  178. % vector_name
  179. )
  180. else:
  181. to_rast_input = vector_name
  182. env = os.environ.copy()
  183. if grass.verbosity() > 1:
  184. env["GRASS_VERBOSE"] = "1"
  185. grass.run_command(
  186. "v.to.rast",
  187. input=to_rast_input,
  188. layer=layer,
  189. output="MASK",
  190. use="val",
  191. val="1",
  192. type="area",
  193. cats=cats,
  194. where=where,
  195. env=env,
  196. )
  197. if invert:
  198. global tmp
  199. tmp = "r_mask_%d" % os.getpid()
  200. grass.run_command("g.rename", raster=("MASK", tmp), quiet=True)
  201. grass.message(_("Creating inverted raster MASK..."))
  202. grass.mapcalc("MASK = if(isnull($tmp), 1, null())", tmp=tmp)
  203. grass.verbose(_("Inverted raster MASK created"))
  204. else:
  205. grass.verbose(_("Raster MASK created"))
  206. grass.message(
  207. _(
  208. "All subsequent raster operations will be limited to "
  209. "the MASK area. Removing or renaming raster map named "
  210. "'MASK' will restore raster operations to normal."
  211. )
  212. )
  213. if __name__ == "__main__":
  214. options, flags = grass.parser()
  215. tmp = tmp_hull = None
  216. atexit.register(cleanup)
  217. main()