1# -*- coding: utf-8 -*- 2""" 3Created on Fri Aug 17 17:24:03 2012 4 5@author: pietro 6""" 7import ctypes 8import datetime 9import grass.lib.vector as libvect 10from grass.pygrass.vector.vector_type import MAPTYPE 11 12from grass.pygrass import utils 13from grass.pygrass.errors import GrassError, OpenError, must_be_open 14from grass.pygrass.vector.table import DBlinks, Link 15from grass.pygrass.vector.find import PointFinder, BboxFinder, PolygonFinder 16 17test_vector_name="abstract_doctest_map" 18 19def is_open(c_mapinfo): 20 """Return if the Vector is open""" 21 return (c_mapinfo.contents.open != 0 and 22 c_mapinfo.contents.open != libvect.VECT_CLOSED_CODE) 23 24 25#============================================= 26# VECTOR ABSTRACT CLASS 27#============================================= 28 29 30class Info(object): 31 """Basic vector info. 32 To get access to the vector info the map must be opened. :: 33 34 >>> test_vect = Info(test_vector_name) 35 >>> test_vect.open(mode='r') 36 37 Then it is possible to read and write the following map attributes: :: 38 39 >>> test_vect.organization 40 'Thuenen Institut' 41 >>> test_vect.person 42 'Soeren Gebbert' 43 >>> test_vect.title 44 'Test dataset' 45 >>> test_vect.scale 46 1 47 >>> test_vect.comment 48 'This is a comment' 49 >>> test_vect.comment = "One useful comment!" 50 >>> test_vect.comment 51 'One useful comment!' 52 53 There are some read only attributes: :: 54 55 >>> test_vect.maptype 56 'native' 57 58 And some basic methods: :: 59 60 >>> test_vect.is_3D() 61 False 62 >>> test_vect.exist() 63 True 64 >>> test_vect.is_open() 65 True 66 >>> test_vect.close() 67 68 """ 69 def __init__(self, name, mapset='', *aopen, **kwopen): 70 self._name = '' 71 self._mapset = '' 72 # Set map name and mapset 73 self.name = name 74 self.mapset = mapset 75 self._aopen = aopen 76 self._kwopen = kwopen 77 self.c_mapinfo = ctypes.pointer(libvect.Map_info()) 78 self._topo_level = 1 79 self._class_name = 'Vector' 80 self._mode = 'r' 81 self.overwrite = False 82 self.date_fmt = '%a %b %d %H:%M:%S %Y' 83 84 def __enter__(self): 85 self.open(*self._aopen, **self._kwopen) 86 return self 87 88 def __exit__(self, exc_type, exc_value, traceback): 89 self.close() 90 91 def _get_mode(self): 92 return self._mode 93 94 def _set_mode(self, mode): 95 if mode.upper() not in 'RW': 96 str_err = _("Mode type: {0} not supported ('r', 'w')") 97 raise ValueError(str_err.format(mode)) 98 self._mode = mode 99 100 mode = property(fget=_get_mode, fset=_set_mode) 101 102 def _get_name(self): 103 """Private method to obtain the Vector name""" 104 return self._name 105 106 def _set_name(self, newname): 107 """Private method to change the Vector name""" 108 if not utils.is_clean_name(newname): 109 str_err = _("Map name {0} not valid") 110 raise ValueError(str_err.format(newname)) 111 self._name = newname 112 113 name = property(fget=_get_name, fset=_set_name, 114 doc="Set or obtain the Vector name") 115 116 def _get_mapset(self): 117 """Private method to obtain the Vector mapset""" 118 return self._mapset 119 120 def _set_mapset(self, mapset): 121 """Private method to change the Vector mapset""" 122 if mapset: 123 self._mapset = mapset 124 125 mapset = property(fget=_get_mapset, fset=_set_mapset, 126 doc="Set or obtain the Vector mapset") 127 128 def _get_organization(self): 129 """Private method to obtain the Vector organization""" 130 return utils.decode(libvect.Vect_get_organization(self.c_mapinfo)) 131 132 def _set_organization(self, org): 133 """Private method to change the Vector organization""" 134 libvect.Vect_set_organization(self.c_mapinfo, org) 135 136 organization = property(fget=_get_organization, fset=_set_organization, 137 doc="Set or obtain the Vector organization") 138 139 def _get_date(self): 140 """Private method to obtain the Vector date""" 141 return utils.decode(libvect.Vect_get_date(self.c_mapinfo)) 142 143 def _set_date(self, date): 144 """Private method to change the Vector date""" 145 return libvect.Vect_set_date(self.c_mapinfo, date) 146 147 date = property(fget=_get_date, fset=_set_date, 148 doc="Set or obtain the Vector date") 149 150 def _get_person(self): 151 """Private method to obtain the Vector person""" 152 return utils.decode(libvect.Vect_get_person(self.c_mapinfo)) 153 154 def _set_person(self, person): 155 """Private method to change the Vector person""" 156 libvect.Vect_set_person(self.c_mapinfo, person) 157 158 person = property(fget=_get_person, fset=_set_person, 159 doc="Set or obtain the Vector author") 160 161 def _get_title(self): 162 """Private method to obtain the Vector title""" 163 return utils.decode(libvect.Vect_get_map_name(self.c_mapinfo)) 164 165 def _set_title(self, title): 166 """Private method to change the Vector title""" 167 libvect.Vect_set_map_name(self.c_mapinfo, title) 168 169 title = property(fget=_get_title, fset=_set_title, 170 doc="Set or obtain the Vector title") 171 172 def _get_map_date(self): 173 """Private method to obtain the Vector map date""" 174 date_str = utils.decode(libvect.Vect_get_map_date(self.c_mapinfo)) 175 try: 176 return datetime.datetime.strptime(date_str, self.date_fmt) 177 except: 178 return date_str 179 180 def _set_map_date(self, datetimeobj): 181 """Private method to change the Vector map date""" 182 date_str = datetimeobj.strftime(self.date_fmt) 183 libvect.Vect_set_map_date(self.c_mapinfo, date_str) 184 185 map_date = property(fget=_get_map_date, fset=_set_map_date, 186 doc="Set or obtain the Vector map date") 187 188 def _get_scale(self): 189 """Private method to obtain the Vector scale""" 190 return libvect.Vect_get_scale(self.c_mapinfo) 191 192 def _set_scale(self, scale): 193 """Private method to set the Vector scale""" 194 return libvect.Vect_set_scale(self.c_mapinfo, ctypes.c_int(scale)) 195 196 scale = property(fget=_get_scale, fset=_set_scale, 197 doc="Set or obtain the Vector scale") 198 199 def _get_comment(self): 200 """Private method to obtain the Vector comment""" 201 return utils.decode(libvect.Vect_get_comment(self.c_mapinfo)) 202 203 def _set_comment(self, comm): 204 """Private method to set the Vector comment""" 205 return libvect.Vect_set_comment(self.c_mapinfo, comm) 206 207 comment = property(fget=_get_comment, fset=_set_comment, 208 doc="Set or obtain the Vector comment") 209 210 def _get_zone(self): 211 """Private method to obtain the Vector projection zone""" 212 return libvect.Vect_get_zone(self.c_mapinfo) 213 214 def _set_zone(self, zone): 215 """Private method to set the Vector projection zone""" 216 return libvect.Vect_set_zone(self.c_mapinfo, ctypes.c_int(zone)) 217 218 zone = property(fget=_get_zone, fset=_set_zone, 219 doc="Set or obtain the Vector projection zone") 220 221 def _get_proj(self): 222 """Private method to obtain the Vector projection code""" 223 return libvect.Vect_get_proj(self.c_mapinfo) 224 225 def _set_proj(self, proj): 226 """Private method to set the Vector projection code""" 227 libvect.Vect_set_proj(self.c_mapinfo, ctypes.c_int(proj)) 228 229 proj = property(fget=_get_proj, fset=_set_proj, 230 doc="Set or obtain the Vector projection code") 231 232 def _get_thresh(self): 233 """Private method to obtain the Vector threshold""" 234 return libvect.Vect_get_thresh(self.c_mapinfo) 235 236 def _set_thresh(self, thresh): 237 """Private method to set the Vector threshold""" 238 return libvect.Vect_set_thresh(self.c_mapinfo, ctypes.c_double(thresh)) 239 240 thresh = property(fget=_get_thresh, fset=_set_thresh, 241 doc="Set or obtain the Vector threshold") 242 243 @property 244 @must_be_open 245 def full_name(self): 246 """Return the full name of Vector""" 247 return libvect.Vect_get_full_name(self.c_mapinfo) 248 249 @property 250 @must_be_open 251 def maptype(self): 252 """Return the map type of Vector""" 253 return MAPTYPE[libvect.Vect_maptype(self.c_mapinfo)] 254 255 @property 256 @must_be_open 257 def proj_name(self): 258 """Return the project name of Vector""" 259 return libvect.Vect_get_proj_name(self.c_mapinfo) 260 261 def write_header(self): 262 """Save the change in the C struct permanently to disk.""" 263 libvect.Vect_write_header(self.c_mapinfo) 264 265 def rename(self, newname): 266 """Method to rename the Vector map 267 268 :param newname: the new name for the Vector map 269 :type newname: str 270 """ 271 if self.exist(): 272 if not self.is_open(): 273 utils.rename(self.name, newname, 'vect') 274 else: 275 raise GrassError("The map is open, not able to renamed it.") 276 self._name = newname 277 278 def is_3D(self): 279 """Return if the Vector is 3D""" 280 return bool(libvect.Vect_is_3d(self.c_mapinfo)) 281 282 def exist(self): 283 """Return if the Vector exists or not""" 284 if self.name: 285 if self.mapset == '': 286 mapset = utils.get_mapset_vector(self.name, self.mapset) 287 self.mapset = mapset if mapset else '' 288 return True if mapset else False 289 return bool(utils.get_mapset_vector(self.name, self.mapset)) 290 else: 291 return False 292 293 def is_open(self): 294 """Return if the Vector is open""" 295 return is_open(self.c_mapinfo) 296 297 def open(self, mode=None, layer=1, overwrite=None, with_z=None, 298 # parameters valid only if mode == 'w' 299 tab_name='', tab_cols=None, link_name=None, link_key='cat', 300 link_db='$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db', 301 link_driver='sqlite'): 302 """Open a Vector map. 303 304 305 :param mode: open a vector map in ``r`` in reading, ``w`` in writing 306 and in ``rw`` read and write mode 307 :type mode: str 308 :param layer: specify the layer that you want to use 309 :type layer: int 310 :param overwrite: valid only for ``w`` mode 311 :type overwrite: bool 312 :param with_z: specify if vector map must be open with third dimension 313 enabled or not. Valid only for ``w`` mode, 314 default: False 315 :type with_z: bool 316 :param tab_name: define the name of the table that will be generate 317 :type tab_name: str 318 :param tab_cols: define the name and type of the columns of the 319 attribute table of the vecto map 320 :type tab_cols: list of pairs 321 :param link_name: define the name of the link connecttion with the 322 database 323 :type link_name: str 324 :param link_key: define the nema of the column that will be use as 325 vector category 326 :type link_key: str 327 :param link_db: define the database connection parameters 328 :type link_db: str 329 :param link_driver: define witch database driver will be used 330 :param link_driver: str 331 332 Some of the parameters are valid only with mode ``w`` or ``rw`` 333 334 See more examples in the documentation of the ``read`` and ``write`` 335 methods 336 """ 337 self.mode = mode if mode else self.mode 338 with_z = libvect.WITH_Z if with_z else libvect.WITHOUT_Z 339 # check if map exists or not 340 if not self.exist() and self.mode != 'w': 341 raise OpenError("Map <%s> not found." % self._name) 342 if libvect.Vect_set_open_level(self._topo_level) != 0: 343 raise OpenError("Invalid access level.") 344 # update the overwrite attribute 345 self.overwrite = overwrite if overwrite is not None else self.overwrite 346 # check if the mode is valid 347 if self.mode not in ('r', 'rw', 'w'): 348 raise ValueError("Mode not supported. Use one of: 'r', 'rw', 'w'.") 349 350 # check if the map exist 351 if self.exist() and self.mode in ('r', 'rw'): 352 # open in READ mode 353 if self.mode == 'r': 354 openvect = libvect.Vect_open_old2(self.c_mapinfo, self.name, 355 self.mapset, str(layer)) 356 # open in READ and WRITE mode 357 elif self.mode == 'rw': 358 openvect = libvect.Vect_open_update2(self.c_mapinfo, self.name, 359 self.mapset, str(layer)) 360 361 # instantiate class attributes 362 self.dblinks = DBlinks(self.c_mapinfo) 363 364 # If it is opened in write mode 365 if self.mode == 'w': 366 openvect = libvect.Vect_open_new(self.c_mapinfo, self.name, with_z) 367 self.dblinks = DBlinks(self.c_mapinfo) 368 369 if self.mode in ('w', 'rw') and tab_cols: 370 # create a link 371 link = Link(layer, 372 link_name if link_name else self.name, 373 tab_name if tab_name else self.name, 374 link_key, link_db, link_driver) 375 # add the new link 376 self.dblinks.add(link) 377 # create the table 378 table = link.table() 379 table.create(tab_cols, overwrite=overwrite) 380 table.conn.commit() 381 382 # check the C function result. 383 if openvect == -1: 384 str_err = "Not able to open the map, C function return %d." 385 raise OpenError(str_err % openvect) 386 387 if len(self.dblinks) == 0: 388 self.layer = layer 389 self.table = None 390 self.n_lines = 0 391 else: 392 self.layer = self.dblinks.by_layer(layer).layer 393 self.table = self.dblinks.by_layer(layer).table() 394 self.n_lines = self.table.n_rows() 395 self.writeable = self.mapset == utils.getenv("MAPSET") 396 # Initialize the finder 397 self.find = {'by_point': PointFinder(self.c_mapinfo, self.table, 398 self.writeable), 399 'by_bbox': BboxFinder(self.c_mapinfo, self.table, 400 self.writeable), 401 'by_polygon': PolygonFinder(self.c_mapinfo, self.table, 402 self.writeable), } 403 self.find_by_point = self.find["by_point"] 404 self.find_by_bbox = self.find["by_bbox"] 405 self.find_by_polygon = self.find["by_polygon"] 406 407 def close(self, build=False): 408 """Method to close the Vector 409 410 :param build: True if the vector map should be build before close it 411 :type build: bool 412 """ 413 if hasattr(self, 'table') and self.table is not None: 414 self.table.conn.close() 415 if self.is_open(): 416 if libvect.Vect_close(self.c_mapinfo) != 0: 417 str_err = 'Error when trying to close the map with Vect_close' 418 raise GrassError(str_err) 419 if ((self.c_mapinfo.contents.mode == libvect.GV_MODE_RW or 420 self.c_mapinfo.contents.mode == libvect.GV_MODE_WRITE) and 421 build): 422 self.build() 423 424 def remove(self): 425 """Remove vector map""" 426 if self.is_open(): 427 self.close() 428 utils.remove(self.name, 'vect') 429 430 def build(self): 431 """Close the vector map and build vector Topology""" 432 self.close() 433 libvect.Vect_set_open_level(1) 434 if libvect.Vect_open_old2(self.c_mapinfo, self.name, 435 self.mapset, '0') != 1: 436 str_err = 'Error when trying to open the vector map.' 437 raise GrassError(str_err) 438 # Vect_build returns 1 on success and 0 on error (bool approach) 439 if libvect.Vect_build(self.c_mapinfo) != 1: 440 str_err = 'Error when trying build topology with Vect_build' 441 raise GrassError(str_err) 442 libvect.Vect_close(self.c_mapinfo) 443 444if __name__ == "__main__": 445 import doctest 446 from grass.pygrass import utils 447 utils.create_test_vector_map(test_vector_name) 448 doctest.testmod() 449