abstract.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. # -*- coding: utf-8 -*-
  2. """
  3. Created on Fri Aug 17 16:05:25 2012
  4. @author: pietro
  5. """
  6. import ctypes
  7. from numpy import isnan
  8. #
  9. # import GRASS modules
  10. #
  11. from grass.script import fatal, warning, gisenv
  12. from grass.script import core as grasscore
  13. #from grass.script import core
  14. #import grass.lib as grasslib
  15. import grass.lib.gis as libgis
  16. import grass.lib.raster as libraster
  17. #
  18. # import pygrass modules
  19. #
  20. from grass.pygrass import functions
  21. from grass.pygrass.gis.region import Region
  22. from grass.pygrass.errors import must_be_open
  23. from grass.pygrass.gis import Mapset
  24. #
  25. # import raster classes
  26. #
  27. from raster_type import TYPE as RTYPE
  28. from category import Category
  29. from history import History
  30. ## Define global variables to not exceed the 80 columns
  31. WARN_OVERWRITE = "Raster map <{0}> already exists and will be overwritten"
  32. INDXOUTRANGE = "The index (%d) is out of range, have you open the map?."
  33. class RasterAbstractBase(object):
  34. """Raster_abstract_base: The base class from which all sub-classes
  35. inherit. It does not implement any row or map access methods:
  36. * Implements raster metadata information access (Type, ...)
  37. * Implements an open method that will be overwritten by the sub-classes
  38. * Implements the close method that might be overwritten by sub-classes
  39. (should work for simple row access)
  40. * Implements get and set region methods
  41. * Implements color, history and category handling
  42. * Renaming, deletion, ...
  43. """
  44. def __init__(self, name, mapset=""):
  45. """The constructor need at least the name of the map
  46. *optional* field is the `mapset`. ::
  47. >>> land = RasterAbstractBase('landcover_1m')
  48. >>> land.name
  49. 'landcover_1m'
  50. >>> land.mapset
  51. ''
  52. >>> land.exist()
  53. True
  54. >>> land.mapset
  55. 'PERMANENT'
  56. ..
  57. """
  58. self.mapset = mapset
  59. self._name = name
  60. ## Private attribute `_fd` that return the file descriptor of the map
  61. self._fd = None
  62. ## Private attribute `_rows` that return the number of rows
  63. # in active window, When the class is instanced is empty and it is set
  64. # when you open the file, using Rast_window_rows()
  65. self._rows = None
  66. ## Private attribute `_cols` that return the number of rows
  67. # in active window, When the class is instanced is empty and it is set
  68. # when you open the file, using Rast_window_cols()
  69. self._cols = None
  70. #self.region = Region()
  71. self.cats = Category()
  72. self.hist = History()
  73. def _get_mtype(self):
  74. return self._mtype
  75. def _set_mtype(self, mtype):
  76. if mtype.upper() not in ('CELL', 'FCELL', 'DCELL'):
  77. #fatal(_("Raser type: {0} not supported".format(mtype) ) )
  78. str_err = "Raster type: {0} not supported ('CELL','FCELL','DCELL')"
  79. raise ValueError(_(str_err).format(mtype))
  80. self._mtype = mtype
  81. self._gtype = RTYPE[self.mtype]['grass type']
  82. mtype = property(fget=_get_mtype, fset=_set_mtype)
  83. def _get_mode(self):
  84. return self._mode
  85. def _set_mode(self, mode):
  86. if mode.upper() not in ('R', 'W'):
  87. str_err = _("Mode type: {0} not supported ('r', 'w')")
  88. raise ValueError(str_err.format(mode))
  89. self._mode = mode
  90. mode = property(fget=_get_mode, fset=_set_mode)
  91. def _get_overwrite(self):
  92. return self._overwrite
  93. def _set_overwrite(self, overwrite):
  94. if overwrite not in (True, False):
  95. str_err = _("Overwrite type: {0} not supported (True/False)")
  96. raise ValueError(str_err.format(overwrite))
  97. self._overwrite = overwrite
  98. overwrite = property(fget=_get_overwrite, fset=_set_overwrite)
  99. def _get_name(self):
  100. """Private method to return the Raster name"""
  101. return self._name
  102. def _set_name(self, newname):
  103. """Private method to change the Raster name"""
  104. if not functions.is_clean_name(newname):
  105. str_err = _("Map name {0} not valid")
  106. raise ValueError(str_err.format(newname))
  107. if self.exist():
  108. self.rename(newname)
  109. self._name = newname
  110. name = property(fget=_get_name, fset=_set_name)
  111. @must_be_open
  112. def _get_rows(self):
  113. """Private method to return the Raster name"""
  114. return self._rows
  115. def _set_unchangeable(self, new):
  116. """Private method to change the Raster name"""
  117. warning(_("Unchangeable attribute"))
  118. rows = property(fget=_get_rows, fset=_set_unchangeable)
  119. @must_be_open
  120. def _get_cols(self):
  121. """Private method to return the Raster name"""
  122. return self._cols
  123. cols = property(fget=_get_cols, fset=_set_unchangeable)
  124. @must_be_open
  125. def _get_range(self):
  126. if self.mtype == 'CELL':
  127. maprange = libraster.Range()
  128. libraster.Rast_read_range(self.name, self.mapset,
  129. ctypes.byref(maprange))
  130. self._min = libgis.CELL()
  131. self._max = libgis.CELL()
  132. self._min.value = maprange.min
  133. self._max.value = maprange.max
  134. else:
  135. maprange = libraster.FPRange()
  136. libraster.Rast_read_fp_range(self.name, self.mapset,
  137. ctypes.byref(maprange))
  138. self._min = libgis.DCELL()
  139. self._max = libgis.DCELL()
  140. libraster.Rast_get_fp_range_min_max(ctypes.byref(maprange),
  141. ctypes.byref(self._min),
  142. ctypes.byref(self._max))
  143. return self._min.value, self._max.value
  144. range = property(fget=_get_range, fset=_set_unchangeable)
  145. @must_be_open
  146. def _get_cats_title(self):
  147. return self.cats.title
  148. @must_be_open
  149. def _set_cats_title(self, newtitle):
  150. self.cats.title = newtitle
  151. cats_title = property(fget=_get_cats_title, fset=_set_cats_title)
  152. def __unicode__(self):
  153. return self.name_mapset()
  154. def __str__(self):
  155. """Return the string of the object"""
  156. return self.__unicode__()
  157. def __len__(self):
  158. return self._rows
  159. def __getitem__(self, key):
  160. """Return the row of Raster object, slice allowed."""
  161. if isinstance(key, slice):
  162. #import pdb; pdb.set_trace()
  163. #Get the start, stop, and step from the slice
  164. return (self.get_row(ii) for ii in xrange(*key.indices(len(self))))
  165. elif isinstance(key, tuple):
  166. x, y = key
  167. return self.get(x, y)
  168. elif isinstance(key, int):
  169. if key < 0: # Handle negative indices
  170. key += self._rows
  171. if key >= self._rows:
  172. fatal(INDXOUTRANGE.format(key))
  173. raise IndexError
  174. return self.get_row(key)
  175. else:
  176. fatal("Invalid argument type.")
  177. def __iter__(self):
  178. """Return a constructor of the class"""
  179. return (self.__getitem__(irow) for irow in xrange(self._rows))
  180. def exist(self):
  181. """Return True if the map already exist, and
  182. set the mapset if were not set.
  183. call the C function `G_find_raster`."""
  184. if self.name:
  185. self.mapset = functions.get_mapset_raster(self.name, self.mapset)
  186. else:
  187. return False
  188. if self.mapset:
  189. return True
  190. else:
  191. return False
  192. def is_open(self):
  193. """Return True if the map is open False otherwise"""
  194. return True if self._fd is not None and self._fd >= 0 else False
  195. @must_be_open
  196. def close(self):
  197. """Close the map"""
  198. libraster.Rast_close(self._fd)
  199. # update rows and cols attributes
  200. self._rows = None
  201. self._cols = None
  202. self._fd = None
  203. def remove(self):
  204. """Remove the map"""
  205. if self.is_open():
  206. self.close()
  207. grasscore.run_command('g.remove', rast=self.name)
  208. def name_mapset(self, name=None, mapset=None):
  209. if name is None:
  210. name = self.name
  211. if mapset is None:
  212. self.exist()
  213. mapset = self.mapset
  214. gis_env = gisenv()
  215. if mapset and mapset != gis_env['MAPSET']:
  216. return "{name}@{mapset}".format(name=name, mapset=mapset)
  217. else:
  218. return name
  219. def rename(self, newname):
  220. """Rename the map"""
  221. if self.exist():
  222. functions.rename(self.name, newname, 'rast')
  223. self._name = newname
  224. def set_from_rast(self, rastname='', mapset=''):
  225. """Set the region that will use from a map, if rastername and mapset
  226. is not specify, use itself.
  227. call C function `Rast_get_cellhd`"""
  228. if self.is_open():
  229. fatal("You cannot change the region if map is open")
  230. raise
  231. region = Region()
  232. if rastname == '':
  233. rastname = self.name
  234. if mapset == '':
  235. mapset = self.mapset
  236. libraster.Rast_get_cellhd(rastname, mapset,
  237. ctypes.byref(region._region))
  238. # update rows and cols attributes
  239. self._rows = libraster.Rast_window_rows()
  240. self._cols = libraster.Rast_window_cols()
  241. @must_be_open
  242. def get_value(self, point, region=None):
  243. """This method returns the pixel value of a given pair of coordinates:
  244. Parameters
  245. ------------
  246. point = pair of coordinates in tuple object
  247. """
  248. if not region:
  249. region = Region()
  250. x, y = functions.coor2pixel(point.coords(), region)
  251. if x < 0 or x > region.cols or y < 0 or y > region.rows:
  252. return None
  253. line = self.get_row(int(x))
  254. return line[int(y)]
  255. @must_be_open
  256. def has_cats(self):
  257. """Return True if the raster map has categories"""
  258. if self.exist():
  259. self.cats.read(self)
  260. self.close()
  261. if len(self.cats) != 0:
  262. return True
  263. return False
  264. @must_be_open
  265. def num_cats(self):
  266. """Return the number of categories"""
  267. return len(self.cats)
  268. @must_be_open
  269. def copy_cats(self, raster):
  270. """Copy categories from another raster map object"""
  271. self.cats.copy(raster.cats)
  272. @must_be_open
  273. def sort_cats(self):
  274. """Sort categories order by range"""
  275. self.cats.sort()
  276. @must_be_open
  277. def read_cats(self):
  278. """Read category from the raster map file"""
  279. self.cats.read(self)
  280. @must_be_open
  281. def write_cats(self):
  282. """Write category to the raster map file"""
  283. self.cats.write(self)
  284. @must_be_open
  285. def read_cats_rules(self, filename, sep=':'):
  286. """Read category from the raster map file"""
  287. self.cats.read_rules(filename, sep)
  288. @must_be_open
  289. def write_cats_rules(self, filename, sep=':'):
  290. """Write category to the raster map file"""
  291. self.cats.write_rules(filename, sep)
  292. @must_be_open
  293. def get_cats(self):
  294. """Return a category object"""
  295. cat = Category()
  296. cat.read(self)
  297. return cat
  298. @must_be_open
  299. def set_cats(self, category):
  300. """The internal categories are copied from this object."""
  301. self.cats.copy(category)
  302. @must_be_open
  303. def get_cat(self, label):
  304. """Return a category given an index or a label"""
  305. return self.cats[label]
  306. @must_be_open
  307. def set_cat(self, label, min_cat, max_cat=None, index=None):
  308. """Set or update a category"""
  309. self.cats.set_cat(index, (label, min_cat, max_cat))