abstract.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. # -*- coding: utf-8 -*-
  2. """
  3. Created on Fri Aug 17 17:24:03 2012
  4. @author: pietro
  5. """
  6. import ctypes
  7. import datetime
  8. import grass.lib.vector as libvect
  9. from vector_type import MAPTYPE
  10. from grass.pygrass import functions
  11. from grass.pygrass.errors import GrassError, OpenError, must_be_open
  12. from table import DBlinks, Link
  13. #=============================================
  14. # VECTOR ABSTRACT CLASS
  15. #=============================================
  16. class Info(object):
  17. """Basic vector info.
  18. To get access to the vector info the map must be opened. ::
  19. >>> cens = Info('census')
  20. >>> cens.open()
  21. Then it is possible to read and write the following map attributes: ::
  22. >>> cens.organization
  23. 'NC OneMap'
  24. >>> cens.person
  25. 'hmitaso'
  26. >>> cens.title
  27. 'Wake County census blocks with attributes, clipped (polygon map)'
  28. >>> cens.map_date
  29. datetime.datetime(2007, 3, 19, 22, 1, 37)
  30. >>> cens.date
  31. ''
  32. >>> cens.scale
  33. 1
  34. >>> cens.comment
  35. ''
  36. >>> cens.comment = "One useful comment!"
  37. >>> cens.comment
  38. 'One useful comment!'
  39. >>> cens.zone
  40. 0
  41. >>> cens.proj
  42. 99
  43. There are some read only attributes: ::
  44. >>> cens.full_name
  45. 'census@PERMANENT'
  46. >>> cens.proj_name
  47. 'Lambert Conformal Conic'
  48. >>> cens.maptype
  49. 'native'
  50. And some basic methods: ::
  51. >>> cens.is_3D()
  52. False
  53. >>> cens.exist()
  54. True
  55. >>> cens.is_open()
  56. True
  57. >>> cens.close()
  58. """
  59. def __init__(self, name, mapset='', layer=None):
  60. self._name = None
  61. self._mapset = None
  62. # Set map name and mapset
  63. self.name = name
  64. self.mapset = mapset
  65. self.c_mapinfo = ctypes.pointer(libvect.Map_info())
  66. self._topo_level = 1
  67. self._class_name = 'Vector'
  68. self.overwrite = False
  69. self.date_fmt = '%a %b %d %H:%M:%S %Y'
  70. self.layer = layer
  71. def _get_name(self):
  72. """Private method to obtain the Vector name"""
  73. if self.exist() and self.is_open():
  74. return libvect.Vect_get_name(self.c_mapinfo)
  75. else:
  76. return self._name
  77. def _set_name(self, newname):
  78. """Private method to change the Vector name"""
  79. if not functions.is_clean_name(newname):
  80. str_err = _("Map name {0} not valid")
  81. raise ValueError(str_err.format(newname))
  82. if self.exist():
  83. self.rename(newname)
  84. self._name = newname
  85. name = property(fget=_get_name, fset=_set_name)
  86. def _get_mapset(self):
  87. """Private method to obtain the Vector name"""
  88. return self._mapset
  89. def _set_mapset(self, mapset):
  90. """Private method to change the Vector name"""
  91. if mapset:
  92. self._mapset = mapset
  93. else:
  94. self._mapset = ''
  95. mapset = property(fget=_get_mapset, fset=_set_mapset)
  96. def _get_organization(self):
  97. """Private method to obtain the Vector organization"""
  98. return libvect.Vect_get_organization(self.c_mapinfo)
  99. def _set_organization(self, org):
  100. """Private method to change the Vector organization"""
  101. libvect.Vect_get_organization(self.c_mapinfo, ctypes.c_char_p(org))
  102. organization = property(fget=_get_organization, fset=_set_organization)
  103. def _get_date(self):
  104. """Private method to obtain the Vector date"""
  105. return libvect.Vect_get_date(self.c_mapinfo)
  106. def _set_date(self, date):
  107. """Private method to change the Vector date"""
  108. return libvect.Vect_set_date(self.c_mapinfo, ctypes.c_char_p(date))
  109. date = property(fget=_get_date, fset=_set_date)
  110. def _get_person(self):
  111. """Private method to obtain the Vector person"""
  112. return libvect.Vect_get_person(self.c_mapinfo)
  113. def _set_person(self, person):
  114. """Private method to change the Vector person"""
  115. libvect.Vect_set_person(self.c_mapinfo, ctypes.c_char_p(person))
  116. person = property(fget=_get_person, fset=_set_person)
  117. def _get_title(self):
  118. """Private method to obtain the Vector title"""
  119. return libvect.Vect_get_map_name(self.c_mapinfo)
  120. def _set_title(self, title):
  121. """Private method to change the Vector title"""
  122. libvect.Vect_set_map_name(self.c_mapinfo, ctypes.c_char_p(title))
  123. title = property(fget=_get_title, fset=_set_title)
  124. def _get_map_date(self):
  125. """Private method to obtain the Vector map date"""
  126. date_str = libvect.Vect_get_map_date(self.c_mapinfo)
  127. return datetime.datetime.strptime(date_str, self.date_fmt)
  128. def _set_map_date(self, datetimeobj):
  129. """Private method to change the Vector map date"""
  130. date_str = datetimeobj.strftime(self.date_fmt)
  131. libvect.Vect_set_map_date(self.c_mapinfo, ctypes.c_char_p(date_str))
  132. map_date = property(fget=_get_map_date, fset=_set_map_date)
  133. def _get_scale(self):
  134. """Private method to obtain the Vector scale"""
  135. return libvect.Vect_get_scale(self.c_mapinfo)
  136. def _set_scale(self, scale):
  137. """Private method to set the Vector scale"""
  138. return libvect.Vect_set_scale(self.c_mapinfo, ctypes.c_int(scale))
  139. scale = property(fget=_get_scale, fset=_set_scale)
  140. def _get_comment(self):
  141. """Private method to obtain the Vector comment"""
  142. return libvect.Vect_get_comment(self.c_mapinfo)
  143. def _set_comment(self, comm):
  144. """Private method to set the Vector comment"""
  145. return libvect.Vect_set_comment(self.c_mapinfo, ctypes.c_char_p(comm))
  146. comment = property(fget=_get_comment, fset=_set_comment)
  147. def _get_zone(self):
  148. """Private method to obtain the Vector projection zone"""
  149. return libvect.Vect_get_zone(self.c_mapinfo)
  150. def _set_zone(self, zone):
  151. """Private method to set the Vector projection zone"""
  152. return libvect.Vect_set_zone(self.c_mapinfo, ctypes.c_int(zone))
  153. zone = property(fget=_get_zone, fset=_set_zone)
  154. def _get_proj(self):
  155. """Private method to obtain the Vector projection code"""
  156. return libvect.Vect_get_proj(self.c_mapinfo)
  157. def _set_proj(self, proj):
  158. """Private method to set the Vector projection code"""
  159. libvect.Vect_set_proj(self.c_mapinfo, ctypes.c_int(proj))
  160. proj = property(fget=_get_proj, fset=_set_proj)
  161. def _get_thresh(self):
  162. """Private method to obtain the Vector threshold"""
  163. return libvect.Vect_get_thresh(self.c_mapinfo)
  164. def _set_thresh(self, thresh):
  165. """Private method to set the Vector threshold"""
  166. return libvect.Vect_set_thresh(self.c_mapinfo, ctypes.c_double(thresh))
  167. thresh = property(fget=_get_thresh, fset=_set_thresh)
  168. @property
  169. @must_be_open
  170. def full_name(self):
  171. """Return the full name of Vector"""
  172. return libvect.Vect_get_full_name(self.c_mapinfo)
  173. @property
  174. @must_be_open
  175. def maptype(self):
  176. """Return the map type of Vector"""
  177. return MAPTYPE[libvect.Vect_maptype(self.c_mapinfo)]
  178. @property
  179. @must_be_open
  180. def proj_name(self):
  181. """Return the project name of Vector"""
  182. return libvect.Vect_get_proj_name(self.c_mapinfo)
  183. def _write_header(self):
  184. libvect.Vect_write_header(self.c_mapinfo)
  185. def rename(self, newname):
  186. """Method to rename the Vector map"""
  187. if self.exist():
  188. functions.rename(self.name, newname, 'vect')
  189. self._name = newname
  190. def is_3D(self):
  191. """Return if the Vector is 3D"""
  192. return bool(libvect.Vect_is_3d(self.c_mapinfo))
  193. def exist(self):
  194. """Return if the Vector exists or not"""
  195. if self._name:
  196. self.mapset = functions.get_mapset_vector(self._name, self.mapset)
  197. else:
  198. return False
  199. if self.mapset:
  200. return True
  201. else:
  202. return False
  203. def is_open(self):
  204. """Return if the Vector is open"""
  205. return (self.c_mapinfo.contents.open != 0 and
  206. self.c_mapinfo.contents.open != libvect.VECT_CLOSED_CODE)
  207. def open(self, mode='r', layer=1, overwrite=None,
  208. # parameters valid only if mode == 'w'
  209. tab_name='', tab_cols=None, link_name=None, link_key='cat',
  210. link_db='$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db',
  211. link_driver='sqlite'):
  212. """Open a Vector map.
  213. Parameters
  214. ----------
  215. mode : string
  216. Open a vector map in ``r`` in reading, ``w`` in writing and
  217. in ``rw`` read and write mode
  218. layer: int, optional
  219. Specify the layer that you want to use
  220. Some parameters are valid only if we open use the writing mode (``w``)
  221. overwrite: bool, optional
  222. valid only for ``w`` mode
  223. tab_name: string, optional
  224. Define the name of the table that will be generate
  225. tab_cols: list of pairs, optional
  226. Define the name and type of the columns of the attribute table
  227. of the vecto map
  228. link_name: string, optional
  229. Define the name of the link connecttion with the database
  230. link_key: string, optional
  231. Define the nema of the column that will be use as vector category
  232. link_db: string, optional
  233. Define the database connection parameters
  234. link_driver: string, optional
  235. Define witch database driver will be used
  236. See more examples in the documentation of the ``read`` and ``write``
  237. methods.
  238. """
  239. # check if map exists or not
  240. if not self.exist() and mode != 'w':
  241. raise OpenError("Map <%s> not found." % self._name)
  242. if libvect.Vect_set_open_level(self._topo_level) != 0:
  243. raise OpenError("Invalid access level.")
  244. # update the overwrite attribute
  245. self.overwrite = overwrite if overwrite is not None else self.overwrite
  246. # check if the mode is valid
  247. if mode not in ('r', 'rw', 'w'):
  248. raise ValueError("Mode not supported. Use one of: 'r', 'rw', 'w'.")
  249. # check if the map exist
  250. if self.exist() and mode in ('r', 'rw'):
  251. # open in READ mode
  252. if mode == 'r':
  253. openvect = libvect.Vect_open_old2(self.c_mapinfo, self.name,
  254. self.mapset, str(layer))
  255. # open in READ and WRITE mode
  256. elif mode == 'rw':
  257. openvect = libvect.Vect_open_update2(self.c_mapinfo, self.name,
  258. self.mapset, str(layer))
  259. # instantiate class attributes
  260. self.dblinks = DBlinks(self.c_mapinfo)
  261. # If it is opened in write mode
  262. if mode == 'w':
  263. openvect = libvect.Vect_open_new(self.c_mapinfo, self.name,
  264. libvect.WITHOUT_Z)
  265. self.dblinks = DBlinks(self.c_mapinfo)
  266. if tab_cols:
  267. # create a link
  268. link = Link(layer,
  269. link_name if link_name else self.name,
  270. tab_name if tab_name else self.name,
  271. link_key, link_db, link_driver)
  272. # add the new link
  273. self.dblinks.add(link)
  274. # create the table
  275. table = link.table()
  276. table.create(tab_cols)
  277. table.conn.commit()
  278. # check the C function result.
  279. if openvect == -1:
  280. str_err = "Not able to open the map, C function return %d."
  281. raise OpenError(str_err % openvect)
  282. if len(self.dblinks) == 0:
  283. self.layer = layer
  284. self.table = None
  285. self.n_lines = 0
  286. else:
  287. self.layer = self.dblinks.by_layer(layer).layer
  288. self.table = self.dblinks.by_layer(layer).table()
  289. self.n_lines = self.table.n_rows()
  290. self.writable = self.mapset == functions.getenv("MAPSET")
  291. def close(self):
  292. """Method to close the Vector"""
  293. if hasattr(self, 'table') and self.table is not None:
  294. self.table.conn.close()
  295. if self.is_open():
  296. if libvect.Vect_close(self.c_mapinfo) != 0:
  297. str_err = 'Error when trying to close the map with Vect_close'
  298. raise GrassError(str_err)
  299. if (self.c_mapinfo.contents.mode == libvect.GV_MODE_RW or
  300. self.c_mapinfo.contents.mode == libvect.GV_MODE_WRITE):
  301. self.build()
  302. def remove(self):
  303. """Remove vector map"""
  304. if self.is_open():
  305. self.close()
  306. functions.remove(self.name,'vect')
  307. def build(self):
  308. """Close the vector map and build vector Topology"""
  309. self.close()
  310. libvect.Vect_set_open_level(1)
  311. if libvect.Vect_open_old2(self.c_mapinfo, self.name,
  312. self.mapset, '0') != 1:
  313. str_err = 'Error when trying to open the vector map.'
  314. raise GrassError(str_err)
  315. # Vect_build returns 1 on success and 0 on error (bool approach)
  316. if libvect.Vect_build(self.c_mapinfo) != 1:
  317. str_err = 'Error when trying build topology with Vect_build'
  318. raise GrassError(str_err)
  319. libvect.Vect_close(self.c_mapinfo)