Selaa lähdekoodia

pygrass vector: Added mapinfo pointer checks and some alive() methods

git-svn-id: https://svn.osgeo.org/grass/grass/trunk@65929 15284696-431f-4ddb-bdfa-cd5b030d7da7
Soeren Gebbert 9 vuotta sitten
vanhempi
commit
2f7456ab42
2 muutettua tiedostoa jossa 89 lisäystä ja 3 poistoa
  1. 12 0
      lib/python/pygrass/errors.py
  2. 77 3
      lib/python/pygrass/vector/geometry.py

+ 12 - 0
lib/python/pygrass/errors.py

@@ -16,3 +16,15 @@ def must_be_open(method):
         else:
         else:
             get_msgr().warning(_("The map is close!"))
             get_msgr().warning(_("The map is close!"))
     return wrapper
     return wrapper
+
+
+def mapinfo_must_be_set(method):
+
+    @wraps(method)
+    def wrapper(self, *args, **kargs):
+        if self.c_mapinfo:
+            return method(self, *args, **kargs)
+        else:
+            raise GrassError(_("The self.c_mapinfo pointer must be "\
+                                 "correctly initiated"))
+    return wrapper

+ 77 - 3
lib/python/pygrass/vector/geometry.py

@@ -14,7 +14,7 @@ import numpy as np
 import grass.lib.gis as libgis
 import grass.lib.gis as libgis
 import grass.lib.vector as libvect
 import grass.lib.vector as libvect
 
 
-from grass.pygrass.errors import GrassError
+from grass.pygrass.errors import GrassError, mapinfo_must_be_set
 
 
 from grass.pygrass.vector.basic import Ilist, Bbox, Cats
 from grass.pygrass.vector.basic import Ilist, Bbox, Cats
 from grass.pygrass.vector import sql
 from grass.pygrass.vector import sql
@@ -297,6 +297,7 @@ class Geo(object):
         else:
         else:
             return False
             return False
 
 
+    @mapinfo_must_be_set
     def read(self):
     def read(self):
         """Read and set the coordinates of the centroid from the vector map,
         """Read and set the coordinates of the centroid from the vector map,
         using the centroid_id and calling the Vect_read_line C function"""
         using the centroid_id and calling the Vect_read_line C function"""
@@ -639,6 +640,13 @@ class Line(Geo):
         pnt.is2D = self.is2D
         pnt.is2D = self.is2D
         return pnt
         return pnt
 
 
+    @mapinfo_must_be_set
+    def alive(self):
+        """Return True if this line is alive or False if this line is
+           dead or its index is out of range.
+        """
+        return(bool(libvect.Vect_line_alive(self.c_mapinfo, self.id)))
+
     def append(self, pnt):
     def append(self, pnt):
         """Appends one point to the end of a line, using the
         """Appends one point to the end of a line, using the
         ``Vect_append_point`` C function.
         ``Vect_append_point`` C function.
@@ -802,6 +810,7 @@ class Line(Geo):
         point.is2D = self.is2D
         point.is2D = self.is2D
         return LineDist(point, dist.value, sp_dist.value, lp_dist.value)
         return LineDist(point, dist.value, sp_dist.value, lp_dist.value)
 
 
+    @mapinfo_must_be_set
     def get_first_cat(self):
     def get_first_cat(self):
         """Fetches FIRST category number for given vector line and field, using
         """Fetches FIRST category number for given vector line and field, using
         the ``Vect_get_line_cat`` C function.
         the ``Vect_get_line_cat`` C function.
@@ -811,7 +820,7 @@ class Line(Geo):
             Not implemented yet.
             Not implemented yet.
         """
         """
         # TODO: add this method.
         # TODO: add this method.
-        libvect.Vect_get_line_cat(self.map, self.id, self.field)
+        # libvect.Vect_get_line_cat(self.c_mapinfo, self.id, self.field)
         pass
         pass
 
 
     def pop(self, indx):
     def pop(self, indx):
@@ -1086,8 +1095,15 @@ class Line(Geo):
         """
         """
         libvect.Vect_reset_line(self.c_points)
         libvect.Vect_reset_line(self.c_points)
 
 
+    @mapinfo_must_be_set
     def nodes(self):
     def nodes(self):
-        """Return the nodes in the line"""
+        """Return the start and end nodes of the line
+
+           This method requires topology build.
+
+           return: A tuple of Node objects that represent the
+                   start and end point of this line.
+        """
         if self.is_with_topology():
         if self.is_with_topology():
             n1 = ctypes.c_int()
             n1 = ctypes.c_int()
             n2 = ctypes.c_int()
             n2 = ctypes.c_int()
@@ -1099,9 +1115,29 @@ class Line(Geo):
 
 
 
 
 class Node(object):
 class Node(object):
+    """Node class for topological analysis of line neighbors.
+
+       Objects of this class will be returned by the node() function
+       of a Line object.
+
+       All methods in this class require a proper setup of the Node
+       objects. Hence, the correct id and a valid pointer to a mapinfo
+       object must be provided in the constructions. Otherwise a segfault
+       may happen.
+
+    """
     def __init__(self, v_id, c_mapinfo):
     def __init__(self, v_id, c_mapinfo):
+        """Construct a Node object
+
+           param v_id: The unique node id
+           param c_mapinfo: A valid pointer to the mapinfo object
+        """
         self.id = v_id  # vector id
         self.id = v_id  # vector id
         self.c_mapinfo = c_mapinfo
         self.c_mapinfo = c_mapinfo
+        self._setup()
+
+    @mapinfo_must_be_set
+    def _setup(self):
         self.is2D = bool(libvect.Vect_is_3d(self.c_mapinfo) != 1)
         self.is2D = bool(libvect.Vect_is_3d(self.c_mapinfo) != 1)
         self.nlines = libvect.Vect_get_node_n_lines(self.c_mapinfo, self.id)
         self.nlines = libvect.Vect_get_node_n_lines(self.c_mapinfo, self.id)
 
 
@@ -1114,6 +1150,14 @@ class Node(object):
     def __repr__(self):
     def __repr__(self):
         return "Node(%d)" % self.id
         return "Node(%d)" % self.id
 
 
+    @mapinfo_must_be_set
+    def alive(self):
+        """Return True if this node is alive or False if this node is
+           dead or its index is out of range.
+        """
+        return(bool(libvect.Vect_node_alive(self.c_mapinfo, self.id)))
+
+    @mapinfo_must_be_set
     def coords(self):
     def coords(self):
         """Return a tuple with the node coordinates."""
         """Return a tuple with the node coordinates."""
         x = ctypes.c_double()
         x = ctypes.c_double()
@@ -1138,6 +1182,7 @@ class Node(object):
             if (not only_in and lid > 0) or (not only_out and lid < 0):
             if (not only_in and lid > 0) or (not only_out and lid < 0):
                 yield lid
                 yield lid
 
 
+    @mapinfo_must_be_set
     def lines(self, only_in=False, only_out=False):
     def lines(self, only_in=False, only_out=False):
         """Return a generator with all lines connected to a node.
         """Return a generator with all lines connected to a node.
 
 
@@ -1149,6 +1194,7 @@ class Node(object):
         for iline in self.ilines(only_in, only_out):
         for iline in self.ilines(only_in, only_out):
             yield Line(v_id=abs(iline), c_mapinfo=self.c_mapinfo)
             yield Line(v_id=abs(iline), c_mapinfo=self.c_mapinfo)
 
 
+    @mapinfo_must_be_set
     def angles(self):
     def angles(self):
         """Return a generator with all lines angles in a node."""
         """Return a generator with all lines angles in a node."""
         for iline in range(self.nlines):
         for iline in range(self.nlines):
@@ -1182,6 +1228,7 @@ class Boundary(Line):
     def __repr__(self):
     def __repr__(self):
         return "Boundary(v_id=%r)" % self.id
         return "Boundary(v_id=%r)" % self.id
 
 
+    @mapinfo_must_be_set
     def _get_centroid(self, side, idonly=False):
     def _get_centroid(self, side, idonly=False):
         if side > 0:
         if side > 0:
             v_id = libvect.Vect_get_area_centroid(self.c_mapinfo, side)
             v_id = libvect.Vect_get_area_centroid(self.c_mapinfo, side)
@@ -1208,6 +1255,7 @@ class Boundary(Line):
         """
         """
         return self._get_centroid(self.left_id, idonly)
         return self._get_centroid(self.left_id, idonly)
 
 
+    @mapinfo_must_be_set
     def get_left_right(self):
     def get_left_right(self):
         """Return left and right value"""
         """Return left and right value"""
 
 
@@ -1265,6 +1313,7 @@ class Centroid(Point):
     def __repr__(self):
     def __repr__(self):
         return "Centoid(%s)" % ', '.join(['%f' % co for co in self.coords()])
         return "Centoid(%s)" % ', '.join(['%f' % co for co in self.coords()])
 
 
+    @mapinfo_must_be_set
     def get_centroid_id(self):
     def get_centroid_id(self):
         """Return the centroid_id, using the c_mapinfo and an area_id
         """Return the centroid_id, using the c_mapinfo and an area_id
         attributes of the class, and calling the Vect_get_area_centroid
         attributes of the class, and calling the Vect_get_area_centroid
@@ -1273,6 +1322,7 @@ class Centroid(Point):
                                                      self.area_id)
                                                      self.area_id)
         return centroid_id if centroid_id != 0 else None
         return centroid_id if centroid_id != 0 else None
 
 
+    @mapinfo_must_be_set
     def get_area_id(self):
     def get_area_id(self):
         """Return the area_id, using the c_mapinfo and an centroid_id
         """Return the area_id, using the c_mapinfo and an centroid_id
         attributes of the class, and calling the Vect_get_centroid_area
         attributes of the class, and calling the Vect_get_centroid_area
@@ -1292,6 +1342,7 @@ class Isle(Geo):
     def __repr__(self):
     def __repr__(self):
         return "Isle(%d)" % (self.id)
         return "Isle(%d)" % (self.id)
 
 
+    @mapinfo_must_be_set
     def boundaries(self):
     def boundaries(self):
         """Return a list of boundaries"""
         """Return a list of boundaries"""
         ilist = Ilist()
         ilist = Ilist()
@@ -1299,31 +1350,37 @@ class Isle(Geo):
                                          ilist.c_ilist)
                                          ilist.c_ilist)
         return ilist
         return ilist
 
 
+    @mapinfo_must_be_set
     def bbox(self, bbox=None):
     def bbox(self, bbox=None):
         """Return bounding box of Isle"""
         """Return bounding box of Isle"""
         bbox = bbox if bbox else Bbox()
         bbox = bbox if bbox else Bbox()
         libvect.Vect_get_isle_box(self.c_mapinfo, self.id, bbox.c_bbox)
         libvect.Vect_get_isle_box(self.c_mapinfo, self.id, bbox.c_bbox)
         return bbox
         return bbox
 
 
+    @mapinfo_must_be_set
     def points(self):
     def points(self):
         """Return a Line object with the outer ring points"""
         """Return a Line object with the outer ring points"""
         line = Line()
         line = Line()
         libvect.Vect_get_isle_points(self.c_mapinfo, self.id, line.c_points)
         libvect.Vect_get_isle_points(self.c_mapinfo, self.id, line.c_points)
         return line
         return line
 
 
+    @mapinfo_must_be_set
     def points_geos(self):
     def points_geos(self):
         """Return a Line object with the outer ring points
         """Return a Line object with the outer ring points
         """
         """
         return libvect.Vect_get_isle_points_geos(self.c_mapinfo, self.id)
         return libvect.Vect_get_isle_points_geos(self.c_mapinfo, self.id)
 
 
+    @mapinfo_must_be_set
     def area_id(self):
     def area_id(self):
         """Returns area id for isle."""
         """Returns area id for isle."""
         return libvect.Vect_get_isle_area(self.c_mapinfo, self.id)
         return libvect.Vect_get_isle_area(self.c_mapinfo, self.id)
 
 
+    @mapinfo_must_be_set
     def alive(self):
     def alive(self):
         """Check if isle is alive or dead (topology required)"""
         """Check if isle is alive or dead (topology required)"""
         return bool(libvect.Vect_isle_alive(self.c_mapinfo, self.id))
         return bool(libvect.Vect_isle_alive(self.c_mapinfo, self.id))
 
 
+    @mapinfo_must_be_set
     def contain_pnt(self, pnt):
     def contain_pnt(self, pnt):
         """Check if point is in area.
         """Check if point is in area.
 
 
@@ -1359,6 +1416,7 @@ class Isles(object):
             self._isles_id = self.get_isles_id()
             self._isles_id = self.get_isles_id()
             self._isles = self.get_isles()
             self._isles = self.get_isles()
 
 
+    @mapinfo_must_be_set
     def __len__(self):
     def __len__(self):
         return libvect.Vect_get_area_num_isles(self.c_mapinfo, self.area_id)
         return libvect.Vect_get_area_num_isles(self.c_mapinfo, self.area_id)
 
 
@@ -1370,11 +1428,13 @@ class Isles(object):
             self.get_isles()
             self.get_isles()
         return self._isles[key]
         return self._isles[key]
 
 
+    @mapinfo_must_be_set
     def get_isles_id(self):
     def get_isles_id(self):
         """Return the id of isles"""
         """Return the id of isles"""
         return [libvect.Vect_get_area_isle(self.c_mapinfo, self.area_id, i)
         return [libvect.Vect_get_area_isle(self.c_mapinfo, self.area_id, i)
                 for i in range(self.__len__())]
                 for i in range(self.__len__())]
 
 
+    @mapinfo_must_be_set
     def get_isles(self):
     def get_isles(self):
         """Return isles"""
         """Return isles"""
         return [Isle(v_id=isle_id, c_mapinfo=self.c_mapinfo)
         return [Isle(v_id=isle_id, c_mapinfo=self.c_mapinfo)
@@ -1442,6 +1502,7 @@ class Area(Geo):
         # get isles
         # get isles
         self.get_isles()
         self.get_isles()
 
 
+    @mapinfo_must_be_set
     def get_points(self, line=None):
     def get_points(self, line=None):
         """Return a Line object with the outer ring
         """Return a Line object with the outer ring
 
 
@@ -1452,6 +1513,7 @@ class Area(Geo):
         libvect.Vect_get_area_points(self.c_mapinfo, self.id, line.c_points)
         libvect.Vect_get_area_points(self.c_mapinfo, self.id, line.c_points)
         return line
         return line
 
 
+    @mapinfo_must_be_set
     def get_centroid(self, centroid=None):
     def get_centroid(self, centroid=None):
         """Return the centroid
         """Return the centroid
 
 
@@ -1467,9 +1529,11 @@ class Area(Geo):
             return Centroid(v_id=centroid_id, c_mapinfo=self.c_mapinfo,
             return Centroid(v_id=centroid_id, c_mapinfo=self.c_mapinfo,
                             area_id=self.id)
                             area_id=self.id)
 
 
+    @mapinfo_must_be_set
     def num_isles(self):
     def num_isles(self):
         return libvect.Vect_get_area_num_isles(self.c_mapinfo, self.id)
         return libvect.Vect_get_area_num_isles(self.c_mapinfo, self.id)
 
 
+    @mapinfo_must_be_set
     def get_isles(self, isles=None):
     def get_isles(self, isles=None):
         """Instantiate the boundary attribute reading area_id"""
         """Instantiate the boundary attribute reading area_id"""
         if isles is not None:
         if isles is not None:
@@ -1477,17 +1541,20 @@ class Area(Geo):
             return isles
             return isles
         return Isles(self.c_mapinfo, self.id)
         return Isles(self.c_mapinfo, self.id)
 
 
+    @mapinfo_must_be_set
     def area(self):
     def area(self):
         """Returns area of area without areas of isles.
         """Returns area of area without areas of isles.
         double Vect_get_area_area (const struct Map_info \*Map, int area)
         double Vect_get_area_area (const struct Map_info \*Map, int area)
         """
         """
         return libvect.Vect_get_area_area(self.c_mapinfo, self.id)
         return libvect.Vect_get_area_area(self.c_mapinfo, self.id)
 
 
+    @mapinfo_must_be_set
     def alive(self):
     def alive(self):
         """Check if area is alive or dead (topology required)
         """Check if area is alive or dead (topology required)
         """
         """
         return bool(libvect.Vect_area_alive(self.c_mapinfo, self.id))
         return bool(libvect.Vect_area_alive(self.c_mapinfo, self.id))
 
 
+    @mapinfo_must_be_set
     def bbox(self, bbox=None):
     def bbox(self, bbox=None):
         """Return the Bbox of area
         """Return the Bbox of area
 
 
@@ -1498,6 +1565,7 @@ class Area(Geo):
         libvect.Vect_get_area_box(self.c_mapinfo, self.id, bbox.c_bbox)
         libvect.Vect_get_area_box(self.c_mapinfo, self.id, bbox.c_bbox)
         return bbox
         return bbox
 
 
+    @mapinfo_must_be_set
     def buffer(self, dist=None, dist_x=None, dist_y=None,
     def buffer(self, dist=None, dist_x=None, dist_y=None,
                angle=0, round_=True, caps=True, tol=0.1):
                angle=0, round_=True, caps=True, tol=0.1):
         """Return the buffer area around the area, using the
         """Return the buffer area around the area, using the
@@ -1537,6 +1605,7 @@ class Area(Geo):
                     isles=[Line(c_points=pp_isle[i].contents)
                     isles=[Line(c_points=pp_isle[i].contents)
                            for i in range(n_isles.contents.value)])
                            for i in range(n_isles.contents.value)])
 
 
+    @mapinfo_must_be_set
     def boundaries(self, ilist=False):
     def boundaries(self, ilist=False):
         """Creates list of boundaries for given area.
         """Creates list of boundaries for given area.
 
 
@@ -1550,6 +1619,7 @@ class Area(Geo):
             return ilist
             return ilist
         return [Boundary(v_id=abs(v_id), c_mapinfo=self.c_mapinfo) for v_id in ilst]
         return [Boundary(v_id=abs(v_id), c_mapinfo=self.c_mapinfo) for v_id in ilst]
 
 
+    @mapinfo_must_be_set
     def cats(self, cats=None):
     def cats(self, cats=None):
         """Get area categories.
         """Get area categories.
 
 
@@ -1564,9 +1634,12 @@ class Area(Geo):
         """Find FIRST category of given field and area.
         """Find FIRST category of given field and area.
 
 
         int Vect_get_area_cat(const struct Map_info \*Map, int area, int field)
         int Vect_get_area_cat(const struct Map_info \*Map, int area, int field)
+
+        ..warning: Not implemented
         """
         """
         pass
         pass
 
 
+    @mapinfo_must_be_set
     def contain_pnt(self, pnt, bbox=None):
     def contain_pnt(self, pnt, bbox=None):
         """Check if point is in area.
         """Check if point is in area.
 
 
@@ -1580,6 +1653,7 @@ class Area(Geo):
                                                self.c_mapinfo, self.id,
                                                self.c_mapinfo, self.id,
                                                bbox.c_bbox))
                                                bbox.c_bbox))
 
 
+    @mapinfo_must_be_set
     def perimeter(self):
     def perimeter(self):
         """Calculate area perimeter.
         """Calculate area perimeter.