abstract.py 10 KB

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