~ubuntu-branches/ubuntu/wily/grass/wily

« back to all changes in this revision

Viewing changes to lib/python/pygrass/vector/__init__.py

Tags: 7.0.0~rc1+ds1-1~exp1
* New upstream release candidate.
* Repack upstream tarball, remove precompiled Python objects.
* Add upstream metadata.
* Update gbp.conf and Vcs-Git URL to use the experimental branch.
* Update watch file for GRASS 7.0.
* Drop build dependencies for Tcl/Tk, add build dependencies:
  python-numpy, libnetcdf-dev, netcdf-bin, libblas-dev, liblapack-dev
* Update Vcs-Browser URL to use cgit instead of gitweb.
* Update paths to use grass70.
* Add configure options: --with-netcdf, --with-blas, --with-lapack,
  remove --with-tcltk-includes.
* Update patches for GRASS 7.
* Update copyright file, changes:
  - Update copyright years
  - Group files by license
  - Remove unused license sections
* Add patches for various typos.
* Fix desktop file with patch instead of d/rules.
* Use minimal dh rules.
* Bump Standards-Version to 3.9.6, no changes.
* Use dpkg-maintscript-helper to replace directories with symlinks.
  (closes: #776349)
* Update my email to use @debian.org address.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
from os.path import join, exists
 
3
import grass.lib.gis as libgis
 
4
libgis.G_gisinit('')
 
5
import grass.lib.vector as libvect
 
6
 
 
7
#
 
8
# import pygrass modules
 
9
#
 
10
from grass.pygrass.vector.vector_type import VTYPE
 
11
from grass.pygrass.errors import GrassError, must_be_open
 
12
from grass.pygrass.gis import Location
 
13
 
 
14
from grass.pygrass.vector.geometry import GEOOBJ as _GEOOBJ
 
15
from grass.pygrass.vector.geometry import read_line, read_next_line
 
16
from grass.pygrass.vector.geometry import Area as _Area
 
17
from grass.pygrass.vector.abstract import Info
 
18
from grass.pygrass.vector.basic import Bbox, Cats, Ilist
 
19
 
 
20
 
 
21
_NUMOF = {"areas": libvect.Vect_get_num_areas,
 
22
          "dblinks": libvect.Vect_get_num_dblinks,
 
23
          "faces": libvect.Vect_get_num_faces,
 
24
          "holes": libvect.Vect_get_num_holes,
 
25
          "islands": libvect.Vect_get_num_islands,
 
26
          "kernels": libvect.Vect_get_num_kernels,
 
27
          "lines": libvect.Vect_get_num_lines,
 
28
          "nodes": libvect.Vect_get_num_nodes,
 
29
          "updated_lines": libvect.Vect_get_num_updated_lines,
 
30
          "updated_nodes": libvect.Vect_get_num_updated_nodes,
 
31
          "volumes": libvect.Vect_get_num_volumes}
 
32
 
 
33
 
 
34
#=============================================
 
35
# VECTOR
 
36
#=============================================
 
37
 
 
38
class Vector(Info):
 
39
    """Vector class is the grass vector format without topology
 
40
 
 
41
        >>> from grass.pygrass.vector import Vector
 
42
        >>> cens = Vector('census')
 
43
        >>> cens.is_open()
 
44
        False
 
45
        >>> cens.mapset
 
46
        ''
 
47
        >>> cens.exist()
 
48
        True
 
49
        >>> cens.mapset
 
50
        'PERMANENT'
 
51
        >>> cens.overwrite
 
52
        False
 
53
 
 
54
    """
 
55
    def __init__(self, name, mapset='', *args, **kwargs):
 
56
        # Set map name and mapset
 
57
        super(Vector, self).__init__(name, mapset, *args, **kwargs)
 
58
        self._topo_level = 1
 
59
        self._class_name = 'Vector'
 
60
        self.overwrite = False
 
61
 
 
62
    def __repr__(self):
 
63
        if self.exist():
 
64
            return "%s(%r, %r)" % (self._class_name, self.name, self.mapset)
 
65
        else:
 
66
            return "%s(%r)" % (self._class_name, self.name)
 
67
 
 
68
    def __iter__(self):
 
69
        """::
 
70
 
 
71
            >>> cens = Vector('census')
 
72
            >>> cens.open(mode='r')
 
73
            >>> features = [feature for feature in cens]
 
74
            >>> features[:3]
 
75
            [Boundary(v_id=None), Boundary(v_id=None), Boundary(v_id=None)]
 
76
            >>> cens.close()
 
77
 
 
78
        ..
 
79
        """
 
80
        #return (self.read(f_id) for f_id in xrange(self.num_of_features()))
 
81
        return self
 
82
 
 
83
    @must_be_open
 
84
    def next(self):
 
85
        """::
 
86
 
 
87
            >>> cens = Vector('census')
 
88
            >>> cens.open(mode='r')
 
89
            >>> cens.next()
 
90
            Boundary(v_id=None)
 
91
            >>> cens.next()
 
92
            Boundary(v_id=None)
 
93
            >>> cens.close()
 
94
 
 
95
        ..
 
96
        """
 
97
        return read_next_line(self.c_mapinfo, self.table, self.writable,
 
98
                              is2D=not self.is_3D())
 
99
 
 
100
    @must_be_open
 
101
    def rewind(self):
 
102
        """Rewind vector map to cause reads to start at beginning."""
 
103
        if libvect.Vect_rewind(self.c_mapinfo) == -1:
 
104
            raise GrassError("Vect_rewind raise an error.")
 
105
 
 
106
    @must_be_open
 
107
    def write(self, geo_obj, attrs=None, set_cats=True):
 
108
        """Write geometry features and attributes.
 
109
 
 
110
        :param geo_obj: a geometry grass object define in
 
111
                        grass.pygrass.vector.geometry
 
112
        :type geo_obj: geometry GRASS object
 
113
        :param attrs: a list with the values that will be insert in the
 
114
                      attribute table.
 
115
        :type attrs: list
 
116
        :param set_cats: if True, the category of the geometry feature is set
 
117
                         using the default layer of the vector map and a
 
118
                         progressive category value (default), otherwise the
 
119
                         c_cats attribute of the geometry object will be used.
 
120
        :type set_cats: bool
 
121
 
 
122
        Open a new vector map ::
 
123
 
 
124
            >>> new = VectorTopo('newvect')
 
125
            >>> new.exist()
 
126
            False
 
127
 
 
128
        define the new columns of the attribute table ::
 
129
 
 
130
            >>> cols = [(u'cat',       'INTEGER PRIMARY KEY'),
 
131
            ...         (u'name',      'TEXT')]
 
132
 
 
133
        open the vector map in write mode
 
134
 
 
135
            >>> new.open('w', tab_name='newvect', tab_cols=cols)
 
136
 
 
137
        import a geometry feature ::
 
138
 
 
139
            >>> from grass.pygrass.vector.geometry import Point
 
140
 
 
141
        create two points ::
 
142
 
 
143
            >>> point0 = Point(636981.336043, 256517.602235)
 
144
            >>> point1 = Point(637209.083058, 257970.129540)
 
145
 
 
146
        then write the two points on the map, with ::
 
147
 
 
148
            >>> new.write(point0, ('pub', ))
 
149
            >>> new.write(point1, ('resturnat', ))
 
150
 
 
151
        commit the db changes ::
 
152
 
 
153
            >>> new.table.conn.commit()
 
154
            >>> new.table.execute().fetchall()
 
155
            [(1, u'pub'), (2, u'resturnat')]
 
156
 
 
157
        close the vector map ::
 
158
 
 
159
            >>> new.close()
 
160
            >>> new.exist()
 
161
            True
 
162
 
 
163
        then play with the map ::
 
164
 
 
165
            >>> new.open(mode='r')
 
166
            >>> new.read(1)
 
167
            Point(636981.336043, 256517.602235)
 
168
            >>> new.read(2)
 
169
            Point(637209.083058, 257970.129540)
 
170
            >>> new.read(1).attrs['name']
 
171
            u'pub'
 
172
            >>> new.read(2).attrs['name']
 
173
            u'resturnat'
 
174
            >>> new.close()
 
175
            >>> new.remove()
 
176
 
 
177
        """
 
178
        self.n_lines += 1
 
179
        if self.table is not None and attrs:
 
180
            attr = [self.n_lines, ]
 
181
            attr.extend(attrs)
 
182
            cur = self.table.conn.cursor()
 
183
            cur.execute(self.table.columns.insert_str, attr)
 
184
            cur.close()
 
185
 
 
186
        if set_cats:
 
187
            cats = Cats(geo_obj.c_cats)
 
188
            cats.reset()
 
189
            cats.set(self.n_lines, self.layer)
 
190
 
 
191
        if geo_obj.gtype == _Area.gtype:
 
192
            result = self._write_area(geo_obj)
 
193
        result = libvect.Vect_write_line(self.c_mapinfo, geo_obj.gtype,
 
194
                                         geo_obj.c_points, geo_obj.c_cats)
 
195
        if result == -1:
 
196
            raise GrassError("Not able to write the vector feature.")
 
197
        if self._topo_level == 2:
 
198
            # return new feature id (on level 2)
 
199
            geo_obj.id = result
 
200
        else:
 
201
            # return offset into file where the feature starts (on level 1)
 
202
            geo_obj.offset = result
 
203
 
 
204
    @must_be_open
 
205
    def has_color_table(self):
 
206
        """Return if vector has color table associated in file system;
 
207
        Color table stored in the vector's attribute table well be not checked
 
208
 
 
209
        >>> cens = Vector('census')
 
210
        >>> cens.open(mode='r')
 
211
        >>> cens.has_color_table()
 
212
        False
 
213
 
 
214
        >>> cens.close()
 
215
        >>> from grass.pygrass.utils import copy, remove
 
216
        >>> copy('census','mycensus','vect')
 
217
        >>> from grass.pygrass.modules.shortcuts import vector as v
 
218
        >>> v.colors(map='mycensus', color='population', column='TOTAL_POP')
 
219
        Module('v.colors')
 
220
        >>> mycens = Vector('mycensus')
 
221
        >>> mycens.open(mode='r')
 
222
        >>> mycens.has_color_table()
 
223
        True
 
224
        >>> mycens.close()
 
225
        >>> remove('mycensus', 'vect')
 
226
        """
 
227
        loc = Location()
 
228
        path = join(loc.path(), self.mapset, 'vector', self.name, 'colr')
 
229
        return True if exists(path) else False
 
230
 
 
231
 
 
232
#=============================================
 
233
# VECTOR WITH TOPOLOGY
 
234
#=============================================
 
235
 
 
236
class VectorTopo(Vector):
 
237
    """Vector class with the support of the GRASS topology.
 
238
 
 
239
    Open a vector map using the *with statement*: ::
 
240
 
 
241
        >>> with VectorTopo('schools', mode='r') as schools:
 
242
        ...     for school in schools[:3]:
 
243
        ...         print school.attrs['NAMESHORT']
 
244
        ...
 
245
        SWIFT CREEK
 
246
        BRIARCLIFF
 
247
        FARMINGTON WOODS
 
248
        >>> schools.is_open()
 
249
        False
 
250
 
 
251
    ..
 
252
    """
 
253
    def __init__(self, name, mapset='', *args, **kwargs):
 
254
        super(VectorTopo, self).__init__(name, mapset, *args, **kwargs)
 
255
        self._topo_level = 2
 
256
        self._class_name = 'VectorTopo'
 
257
 
 
258
    def __len__(self):
 
259
        return libvect.Vect_get_num_lines(self.c_mapinfo)
 
260
 
 
261
    def __getitem__(self, key):
 
262
        """::
 
263
 
 
264
            >>> cens = VectorTopo('census')
 
265
            >>> cens.open(mode='r')
 
266
            >>> cens[:3]
 
267
            [Boundary(v_id=1), Boundary(v_id=2), Boundary(v_id=3)]
 
268
            >>> cens.close()
 
269
 
 
270
        ..
 
271
        """
 
272
        if isinstance(key, slice):
 
273
            return [self.read(indx)
 
274
                    for indx in range(key.start if key.start else 1,
 
275
                                      key.stop if key.stop else len(self),
 
276
                                      key.step if key.step else 1)]
 
277
        elif isinstance(key, int):
 
278
            return self.read(key)
 
279
        else:
 
280
            raise ValueError("Invalid argument type: %r." % key)
 
281
 
 
282
    @must_be_open
 
283
    def num_primitive_of(self, primitive):
 
284
        """Return the number of primitive
 
285
 
 
286
        :param primitive: the name of primitive to query; the supported values are:
 
287
 
 
288
                            * *boundary*,
 
289
                            * *centroid*,
 
290
                            * *face*,
 
291
                            * *kernel*,
 
292
                            * *line*,
 
293
                            * *point*
 
294
                            * *area*
 
295
                            * *volume*
 
296
 
 
297
        :type primitive: str
 
298
 
 
299
        ::
 
300
 
 
301
            >>> cens = VectorTopo('census')
 
302
            >>> cens.open(mode='r')
 
303
            >>> cens.num_primitive_of('point')
 
304
            0
 
305
            >>> cens.num_primitive_of('line')
 
306
            0
 
307
            >>> cens.num_primitive_of('centroid')
 
308
            2537
 
309
            >>> cens.num_primitive_of('boundary')
 
310
            6383
 
311
            >>> cens.close()
 
312
 
 
313
        ..
 
314
        """
 
315
        return libvect.Vect_get_num_primitives(self.c_mapinfo,
 
316
                                               VTYPE[primitive])
 
317
 
 
318
    @must_be_open
 
319
    def number_of(self, vtype):
 
320
        """Return the number of the choosen element type
 
321
 
 
322
        :param vtype: the name of type to query; the supported values are:
 
323
                      *areas*, *dblinks*, *faces*, *holes*, *islands*,
 
324
                      *kernels*, *line_points*, *lines*, *nodes*,
 
325
                      *update_lines*, *update_nodes*, *volumes*
 
326
        :type vtype: str
 
327
 
 
328
            >>> cens = VectorTopo('census')
 
329
            >>> cens.open(mode='r')
 
330
            >>> cens.number_of("areas")
 
331
            2547
 
332
            >>> cens.number_of("islands")
 
333
            49
 
334
            >>> cens.number_of("holes")
 
335
            0
 
336
            >>> cens.number_of("lines")
 
337
            8920
 
338
            >>> cens.number_of("nodes")
 
339
            3885
 
340
            >>> cens.number_of("pizza")
 
341
            ...                     # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
 
342
            Traceback (most recent call last):
 
343
                ...
 
344
            ValueError: vtype not supported, use one of: 'areas', ...
 
345
            >>> cens.close()
 
346
 
 
347
 
 
348
        ..
 
349
        """
 
350
        if vtype in _NUMOF.keys():
 
351
            return _NUMOF[vtype](self.c_mapinfo)
 
352
        else:
 
353
            keys = "', '".join(sorted(_NUMOF.keys()))
 
354
            raise ValueError("vtype not supported, use one of: '%s'" % keys)
 
355
 
 
356
    @must_be_open
 
357
    def num_primitives(self):
 
358
        """Return dictionary with the number of all primitives
 
359
        """
 
360
        output = {}
 
361
        for prim in VTYPE.keys():
 
362
            output[prim] = self.num_primitive_of(prim)
 
363
        return output
 
364
 
 
365
    @must_be_open
 
366
    def viter(self, vtype, idonly=False):
 
367
        """Return an iterator of vector features
 
368
 
 
369
        :param vtype: the name of type to query; the supported values are:
 
370
                      *areas*, *dblinks*, *faces*, *holes*, *islands*,
 
371
                      *kernels*, *line_points*, *lines*, *nodes*,
 
372
                      *update_lines*, *update_nodes*, *volumes*
 
373
        :type vtype: str
 
374
        :param idonly: variable to return only the id of features instead of
 
375
                       full features
 
376
        :type idonly: bool
 
377
 
 
378
            >>> cens = VectorTopo('census', mode='r')
 
379
            >>> cens.open(mode='r')
 
380
            >>> big = [area for area in cens.viter('areas')
 
381
            ...        if area.alive() and area.area() >= 10000]
 
382
            >>> big[:3]
 
383
            [Area(5), Area(6), Area(13)]
 
384
 
 
385
 
 
386
        to sort the result in a efficient way, use: ::
 
387
 
 
388
            >>> from operator import methodcaller as method
 
389
            >>> big.sort(key=method('area'), reverse=True)  # sort the list
 
390
            >>> for area in big[:3]:
 
391
            ...     print area, area.area()
 
392
            Area(2099) 5392751.5304
 
393
            Area(2171) 4799921.30863
 
394
            Area(495) 4055812.49695
 
395
            >>> cens.close()
 
396
 
 
397
        """
 
398
        if vtype in _GEOOBJ.keys():
 
399
            if _GEOOBJ[vtype] is not None:
 
400
                ids = (indx for indx in range(1, self.number_of(vtype) + 1))
 
401
                if idonly:
 
402
                    return ids
 
403
                return (_GEOOBJ[vtype](v_id=indx, c_mapinfo=self.c_mapinfo,
 
404
                                       table=self.table,
 
405
                                       writable=self.writable)
 
406
                        for indx in ids)
 
407
        else:
 
408
            keys = "', '".join(sorted(_GEOOBJ.keys()))
 
409
            raise ValueError("vtype not supported, use one of: '%s'" % keys)
 
410
 
 
411
    @must_be_open
 
412
    def rewind(self):
 
413
        """Rewind vector map to cause reads to start at beginning. ::
 
414
 
 
415
            >>> cens = VectorTopo('census')
 
416
            >>> cens.open(mode='r')
 
417
            >>> cens.next()
 
418
            Boundary(v_id=1)
 
419
            >>> cens.next()
 
420
            Boundary(v_id=2)
 
421
            >>> cens.next()
 
422
            Boundary(v_id=3)
 
423
            >>> cens.rewind()
 
424
            >>> cens.next()
 
425
            Boundary(v_id=1)
 
426
            >>> cens.close()
 
427
 
 
428
        ..
 
429
        """
 
430
        libvect.Vect_rewind(self.c_mapinfo)
 
431
 
 
432
    @must_be_open
 
433
    def cat(self, cat_id, vtype, layer=None, generator=False, geo=None):
 
434
        """Return the geometry features with category == cat_id.
 
435
 
 
436
        :param cat_id: the category number
 
437
        :type cat_id: int
 
438
        :param vtype: the type of geometry feature that we are looking for
 
439
        :type vtype: str
 
440
        :param layer: the layer number that will be used
 
441
        :type layer: int
 
442
        :param generator: if True return a generator otherwise it return a
 
443
                          list of features
 
444
        :type generator: bool
 
445
        """
 
446
        if geo is None and vtype not in _GEOOBJ:
 
447
            keys = "', '".join(sorted(_GEOOBJ.keys()))
 
448
            raise ValueError("vtype not supported, use one of: '%s'" % keys)
 
449
        Obj = _GEOOBJ[vtype] if geo is None else geo
 
450
        ilist = Ilist()
 
451
        libvect.Vect_cidx_find_all(self.c_mapinfo,
 
452
                                   layer if layer else self.layer,
 
453
                                   Obj.gtype, cat_id, ilist.c_ilist)
 
454
        is2D = not self.is_3D()
 
455
        if generator:
 
456
            return (read_line(feature_id=v_id, c_mapinfo=self.c_mapinfo,
 
457
                              table=self.table, writable=self.writable,
 
458
                              is2D=is2D)
 
459
                    for v_id in ilist)
 
460
        else:
 
461
            return [read_line(feature_id=v_id, c_mapinfo=self.c_mapinfo,
 
462
                              table=self.table, writable=self.writable,
 
463
                              is2D=is2D)
 
464
                    for v_id in ilist]
 
465
 
 
466
    @must_be_open
 
467
    def read(self, feature_id):
 
468
        """Return a geometry object given the feature id.
 
469
 
 
470
        :param int feature_id: the id of feature to obtain
 
471
 
 
472
        >>> cens = VectorTopo('census')
 
473
        >>> cens.open(mode='r')
 
474
        >>> feature1 = cens.read(0)                     #doctest: +ELLIPSIS
 
475
        Traceback (most recent call last):
 
476
            ...
 
477
        ValueError: The index must be >0, 0 given.
 
478
        >>> feature1 = cens.read(1)
 
479
        >>> feature1
 
480
        Boundary(v_id=1)
 
481
        >>> feature1.length()
 
482
        444.54490917696944
 
483
        >>> cens.read(-1)
 
484
        Centoid(642963.159711, 214994.016279)
 
485
        >>> len(cens)
 
486
        8920
 
487
        >>> cens.read(8920)
 
488
        Centoid(642963.159711, 214994.016279)
 
489
        >>> cens.read(8921)                             #doctest: +ELLIPSIS
 
490
        Traceback (most recent call last):
 
491
          ...
 
492
        IndexError: Index out of range
 
493
        >>> cens.close()
 
494
 
 
495
        """
 
496
        return read_line(feature_id, self.c_mapinfo, self.table, self.writable,
 
497
                         is2D=not self.is_3D())
 
498
 
 
499
    @must_be_open
 
500
    def is_empty(self):
 
501
        """Return if a vector map is empty or not
 
502
        """
 
503
        primitives = self.num_primitives()
 
504
        output = True
 
505
        for v in primitives.values():
 
506
            if v != 0:
 
507
                output = False
 
508
                break
 
509
        return output
 
510
 
 
511
    @must_be_open
 
512
    def rewrite(self, line, geo_obj, attrs=None, **kargs):
 
513
        """Rewrite a geometry features
 
514
        """
 
515
        if self.table is not None and attrs:
 
516
            attr = [line, ]
 
517
            attr.extend(attrs)
 
518
            self.table.update(key=line, values=attr)
 
519
        elif self.table is None and attrs:
 
520
            print "Table for vector {name} does not exist, attributes not" \
 
521
                  " loaded".format(name=self.name)
 
522
        libvect.Vect_cat_set(geo_obj.c_cats, self.layer, line)
 
523
        result = libvect.Vect_rewrite_line(self.c_mapinfo,
 
524
                                           line, geo_obj.gtype,
 
525
                                           geo_obj.c_points,
 
526
                                           geo_obj.c_cats)
 
527
        if result == -1:
 
528
            raise GrassError("Not able to write the vector feature.")
 
529
 
 
530
        # return offset into file where the feature starts
 
531
        geo_obj.offset = result
 
532
 
 
533
    @must_be_open
 
534
    def delete(self, feature_id):
 
535
        """Remove a feature by its id
 
536
 
 
537
        :param feature_id: the id of the feature
 
538
        :type feature_id: int
 
539
        """
 
540
        if libvect.Vect_rewrite_line(self.c_mapinfo, feature_id) == -1:
 
541
            raise GrassError("C funtion: Vect_rewrite_line.")
 
542
 
 
543
    @must_be_open
 
544
    def restore(self, geo_obj):
 
545
        if hasattr(geo_obj, 'offset'):
 
546
            if libvect.Vect_restore_line(self.c_mapinfo, geo_obj.id,
 
547
                                         geo_obj.offset) == -1:
 
548
                raise GrassError("C funtion: Vect_restore_line.")
 
549
        else:
 
550
            raise ValueError("The value have not an offset attribute.")
 
551
 
 
552
    @must_be_open
 
553
    def bbox(self):
 
554
        """Return the BBox of the vecor map
 
555
        """
 
556
        bbox = Bbox()
 
557
        if libvect.Vect_get_map_box(self.c_mapinfo, bbox.c_bbox) == 0:
 
558
            raise GrassError("I can not find the Bbox.")
 
559
        return bbox
 
560
 
 
561
    @must_be_open
 
562
    def select_by_bbox(self, bbox):
 
563
        """Return the BBox of the vector map
 
564
        """
 
565
        # TODO replace with bbox if bbox else Bbox() ??
 
566
        bbox = Bbox()
 
567
        if libvect.Vect_get_map_box(self.c_mapinfo, bbox.c_bbox) == 0:
 
568
            raise GrassError("I can not find the Bbox.")
 
569
        return bbox
 
570
 
 
571
    def close(self, build=True, release=True):
 
572
        """Close the VectorTopo map, if release is True, the memory
 
573
        occupied by spatial index is released"""
 
574
        if release:
 
575
            libvect.Vect_set_release_support(self.c_mapinfo)
 
576
        super(VectorTopo, self).close(build=build)