Przeglądaj źródła

pygrass vector: Better finder class documentation, usage and additional tests using the generated vector maps.
Additional metadata for test vectors and better description.


git-svn-id: https://svn.osgeo.org/grass/grass/trunk@66027 15284696-431f-4ddb-bdfa-cd5b030d7da7

Soeren Gebbert 10 lat temu
rodzic
commit
0cea46c98e

+ 97 - 12
lib/python/pygrass/utils.py

@@ -355,14 +355,28 @@ def create_test_vector_map(map_name="test_vector"):
 
 
        This should be used in doc and unit tests to create location/mapset
        This should be used in doc and unit tests to create location/mapset
        independent vector map layer. This map includes 3 points, 3 lines,
        independent vector map layer. This map includes 3 points, 3 lines,
-       11 boundaries and 4 centroids. The attribute table contains cat and name
-       columns.
+       11 boundaries and 4 centroids. The attribute table contains cat, name
+       and value columns.
 
 
         param map_name: The vector map name that should be used
         param map_name: The vector map name that should be used
+
+
+
+                                  P1 P2 P3
+           6                       *  *  *
+           5
+           4    _______ ___ ___   L1 L2 L3
+        Y  3   |A1___ *|  *|  *|   |  |  |
+           2   | |A2*| |   |   |   |  |  |
+           1   | |___| |A3 |A4 |   |  |  |
+           0   |_______|___|___|   |  |  |
+          -1
+            -1 0 1 2 3 4 5 6 7 8 9 10 12 14
+                           X
     """
     """
 
 
     from grass.pygrass.vector import VectorTopo
     from grass.pygrass.vector import VectorTopo
-    from grass.pygrass.vector.geometry import Point, Line, Centroid, Boundary, Area
+    from grass.pygrass.vector.geometry import Point, Line, Centroid, Boundary
 
 
     cols = [(u'cat', 'INTEGER PRIMARY KEY'),
     cols = [(u'cat', 'INTEGER PRIMARY KEY'),
             (u'name','varchar(50)'),
             (u'name','varchar(50)'),
@@ -370,15 +384,6 @@ def create_test_vector_map(map_name="test_vector"):
     with VectorTopo(map_name, mode='w', tab_name=map_name,
     with VectorTopo(map_name, mode='w', tab_name=map_name,
                     tab_cols=cols) as vect:
                     tab_cols=cols) as vect:
 
 
-        # Write 3 points, 3 lines and 11 boundaries with one nested isle and 4 centroids
-        #
-        #
-        #  ______ ___ ___   *  *  *
-        # |1 __ *|3 *|4 *|  |  |  |
-        # | |2*| |   |   |  |  |  |
-        # | |__| |   |   |  |  |  |
-        # |______|___|___|  |  |  |
-        #
         # Write 3 points
         # Write 3 points
         vect.write(Point(10, 6), cat=1, attrs=("point", 1))
         vect.write(Point(10, 6), cat=1, attrs=("point", 1))
         vect.write(Point(12, 6), cat=1)
         vect.write(Point(12, 6), cat=1)
@@ -408,5 +413,85 @@ def create_test_vector_map(map_name="test_vector"):
         vect.write(Centroid(x=5.5, y=3.5), cat=3)
         vect.write(Centroid(x=5.5, y=3.5), cat=3)
         vect.write(Centroid(x=7.5, y=3.5), cat=3)
         vect.write(Centroid(x=7.5, y=3.5), cat=3)
 
 
+        vect.organization = 'Thuenen Institut'
+        vect.person = 'Soeren Gebbert'
+        vect.title = 'Test dataset'
+        vect.comment = 'This is a comment'
+
         vect.table.conn.commit()
         vect.table.conn.commit()
         vect.close()
         vect.close()
+
+def create_test_stream_network_map(map_name="streams"):
+    """
+       This functions creates a vector map layer with lines that represent
+       a stream network with two different graphs. The first graph
+       contains a loop, the second can be used as directed graph.
+
+       This should be used in doc and unit tests to create location/mapset
+       independent vector map layer.
+
+        param map_name: The vector map name that should be used
+
+       1(0,2)  3(2,2)
+        \     /
+       1 \   / 2
+          \ /
+           2(1,1)
+    6(0,1) ||  5(2,1)
+       5 \ || / 4
+          \||/
+           4(1,0)
+           |
+           | 6
+           |7(1,-1)
+
+       7(0,-1) 8(2,-1)
+        \     /
+       8 \   / 9
+          \ /
+           9(1, -2)
+           |
+           | 10
+           |
+          10(1,-3)
+    """
+
+    from grass.pygrass.vector import VectorTopo
+    from grass.pygrass.vector.geometry import Line
+
+    cols = [(u'cat', 'INTEGER PRIMARY KEY'), (u'id', 'INTEGER')]
+    with VectorTopo(map_name, mode='w', tab_name=map_name,
+                    tab_cols=cols) as streams:
+
+        # First flow graph
+        l = Line([(0,2), (0.22, 1.75), (0.55, 1.5), (1,1)])
+        streams.write(l, cat=1, attrs=(1,))
+        l = Line([(2,2),(1,1)])
+        streams.write(l, cat=2, attrs=(2,))
+        l = Line([(1,1), (0.85, 0.5), (1,0)])
+        streams.write(l, cat=3, attrs=(3,))
+        l = Line([(2,1),(1,0)])
+        streams.write(l, cat=4, attrs=(4,))
+        l = Line([(0,1),(1,0)])
+        streams.write(l, cat=5, attrs=(5,))
+        l = Line([(1,0),(1,-1)])
+        streams.write(l, cat=6, attrs=(6,))
+        # Reverse line 3
+        l = Line([(1,0), (1.15, 0.5),(1,1)])
+        streams.write(l, cat=7, attrs=(7,))
+
+        # second flow graph
+        l = Line([(0,-1),(1,-2)])
+        streams.write(l, cat=8, attrs=(8,))
+        l = Line([(2,-1),(1,-2)])
+        streams.write(l, cat=9, attrs=(9,))
+        l = Line([(1,-2),(1,-3)])
+        streams.write(l, cat=10, attrs=(10,))
+
+        streams.organization = 'Thuenen Institut'
+        streams.person = 'Soeren Gebbert'
+        streams.title = 'Test dataset for stream networks'
+        streams.comment = 'This is a comment'
+
+        streams.table.conn.commit()
+        streams.close()

+ 0 - 10
lib/python/pygrass/vector/__init__.py

@@ -562,16 +562,6 @@ class VectorTopo(Vector):
             raise GrassError("I can not find the Bbox.")
             raise GrassError("I can not find the Bbox.")
         return bbox
         return bbox
 
 
-    @must_be_open
-    def select_by_bbox(self, bbox):
-        """Return the BBox of the vector map
-        """
-        # TODO replace with bbox if bbox else Bbox() ??
-        bbox = Bbox()
-        if libvect.Vect_get_map_box(self.c_mapinfo, bbox.c_bbox) == 0:
-            raise GrassError("I can not find the Bbox.")
-        return bbox
-
     def close(self, build=True, release=True):
     def close(self, build=True, release=True):
         """Close the VectorTopo map, if release is True, the memory
         """Close the VectorTopo map, if release is True, the memory
         occupied by spatial index is released"""
         occupied by spatial index is released"""

+ 7 - 2
lib/python/pygrass/vector/abstract.py

@@ -377,13 +377,18 @@ class Info(object):
             self.layer = self.dblinks.by_layer(layer).layer
             self.layer = self.dblinks.by_layer(layer).layer
             self.table = self.dblinks.by_layer(layer).table()
             self.table = self.dblinks.by_layer(layer).table()
             self.n_lines = self.table.n_rows()
             self.n_lines = self.table.n_rows()
-        self.writeable = self.mapset == utils.getenv("MAPSET")
+        self.writeable = False
+        self.mapset == utils.getenv("MAPSET")
+        # Initialize the finder
         self.find = {'by_point': PointFinder(self.c_mapinfo, self.table,
         self.find = {'by_point': PointFinder(self.c_mapinfo, self.table,
                                              self.writeable),
                                              self.writeable),
-                     'by_box': BboxFinder(self.c_mapinfo, self.table,
+                     'by_bbox': BboxFinder(self.c_mapinfo, self.table,
                                           self.writeable),
                                           self.writeable),
                      'by_polygon': PolygonFinder(self.c_mapinfo, self.table,
                      'by_polygon': PolygonFinder(self.c_mapinfo, self.table,
                                                  self.writeable), }
                                                  self.writeable), }
+        self.find_by_point = self.find["by_point"]
+        self.find_by_bbox  = self.find["by_bbox"]
+        self.find_by_polygon = self.find["by_polygon"]
 
 
     def close(self, build=False):
     def close(self, build=False):
         """Method to close the Vector
         """Method to close the Vector

+ 467 - 73
lib/python/pygrass/vector/find.py

@@ -35,60 +35,119 @@ class AbstractFinder(object):
         from . import abstract
         from . import abstract
         return abstract.is_open(self.c_mapinfo)
         return abstract.is_open(self.c_mapinfo)
 
 
-
 class PointFinder(AbstractFinder):
 class PointFinder(AbstractFinder):
-    """PointFinder
-
-    Find the geometry features of a vector map that are close to a point.
-
-    >>> from grass.pygrass.vector import VectorTopo
-    >>> zipcodes = VectorTopo('zipcodes', 'PERMANENT')
-    >>> schools = VectorTopo('schools', 'PERMANENT')
-    >>> zipcodes.open('r')
-    >>> schools.open('r')
-    >>> result = []
-    >>> for school in schools:
-    ...     zipcode = zipcodes.find['by_point'].area(school)
-    ...     result.append((school.attrs['NAMESHORT'],
-    ...                    zipcode.attrs['ZIPCODE']))
-    ...
-    >>> result[0]
-    (u'SWIFT CREEK', u'RALEIGH 27606')
-    >>> result[1]
-    (u'BRIARCLIFF', u'CARY 27511')
-    >>> result[2]
-    (u'FARMINGTON WOODS', u'CARY 27511')
-    >>> from grass.pygrass.vector.geometry import Point
-    >>> pnt = Point(631213.349291, 224684.900084)
-    >>> school = schools.find['by_point'].geo(pnt, maxdist=300.)
-    >>> school.attrs['NAMELONG']
-    u'ADAMS ELEMENTARY'
-    >>> for school in schools.find['by_point'].geos(pnt, maxdist=1000.):
-    ...     print school.attrs['NAMELONG']
-    ...
-    CARY HIGH
-    EAST CARY MIDDLE SITE
-    ADAMS ELEMENTARY
-    >>> schools.close()
-    >>> zipcodes.close()
+    """Point finder
+
+        This class provides an interface to search geometry features
+        of a vector map that are close to a point. The PointFinder class
+        is part of a topological vector map object.
     """
     """
     def __init__(self, c_mapinfo, table=None, writeable=False):
     def __init__(self, c_mapinfo, table=None, writeable=False):
-        """Find geometry feature around a point.
+        """Find geometry feature(s) around a point.
+
+            :param c_mapinfo: Pointer to the vector layer mapinfo structure
+            :type c_mapinfo: ctypes pointer to mapinfo structure
+
+            :param table: Attribute table of the vector layer
+            :type table: Class Table from grass.pygrass.table
+
+            :param writable: True or False
+            :type writeable: boolean
         """
         """
         super(PointFinder, self).__init__(c_mapinfo, table, writeable)
         super(PointFinder, self).__init__(c_mapinfo, table, writeable)
 
 
-# TODO: add the Node class and enable this method
-#    def node(self, point, maxdist):
-#        """Find the nearest node. Vect_find_node"""
-#        i = libvect.Vect_find_node(self.c_mapinfo, point.x, point.y, point.z,
-#                                   float(maxdist), int(not point.is2D))
-#        return geometry.Node(self.c_mapinfo.contents.plus.contents.Node[i])
+    @must_be_open
+    def node(self, point, maxdist):
+        """Find the nearest node around a specific point.
+
+            :param point: The point to search
+            :type point: grass.pygrass.vector.geometry.Point
+
+            :param maxdist: The maximum search distance around the point
+            :type maxdist: float
+
+            :return: A grass.pygrass.vector.geometry.Node if found or None
+
+            This methods uses libvect.Vect_find_node()()
+
+            Examples:
+
+            >>> from grass.pygrass.vector import VectorTopo
+            >>> from grass.pygrass.vector.geometry import Point
+            >>> test_vect = VectorTopo(test_vector_name)
+            >>> test_vect.open('r')
+
+            # Find nearest node
+            >>> points = (Point(10,0), Point(10,4), Point(14,0))
+            >>> result = []
+            >>> for point in points:
+            ...     f = test_vect.find_by_point.node(point=point, maxdist=1)
+            ...     if f:
+            ...         result.append(f)
+            >>> result
+            [Node(2), Node(1), Node(6)]
+
+            >>> test_vect.find_by_point.node(point=Point(20,20), maxdist=0)
+
+            >>> test_vect.close()
+        """
+        node_id = libvect.Vect_find_node(self.c_mapinfo, point.x,
+                                         point.y,
+                                         point.z if point.z else 0,
+                                         float(maxdist),
+                                         int(not point.is2D))
+        if node_id:
+            return Node(v_id=node_id, c_mapinfo=self.c_mapinfo,
+                 table=self.table, writeable=self.writeable)
 
 
     @must_be_open
     @must_be_open
     def geo(self, point, maxdist, type='all', exclude=0):
     def geo(self, point, maxdist, type='all', exclude=0):
-        """Find the nearest line. Vect_find_line
+        """Find the nearest vector feature around a specific point.
+
+            :param point: The point to search
+            :type point: grass.pygrass.vector.geometry.Point
+
+            :param maxdist: The maximum search distance around the point
+            :type maxdist: float
+
+            :param type: The type of feature to search for
+                         Valid type are all the keys in find.vtype dictionary
+            :type type: string
+
+            :param exclude: if > 0 number of lines which should be
+                            excluded from selection
+
+            :return: A grass.pygrass.vector.geometry.Node if found or None
 
 
-        Valid type are all the keys in find.vtype dictionary
+            This methods uses libvect.Vect_find_line()()
+
+            Examples:
+
+            >>> from grass.pygrass.vector import VectorTopo
+            >>> from grass.pygrass.vector.geometry import Point
+            >>> test_vect = VectorTopo(test_vector_name)
+            >>> test_vect.open('r')
+
+            # Find single features
+            >>> points = (Point(10,0), Point(10,6), Point(14,2))
+            >>> result = []
+            >>> for point in points:
+            ...     f = test_vect.find_by_point.geo(point=point, maxdist=1)
+            ...     if f:
+            ...         result.append(f)
+            >>> for f in result:
+            ...     print(f.to_wkt())    #doctest: +NORMALIZE_WHITESPACE
+            LINESTRING(10.000000 4.000000,
+                       10.000000 2.000000,
+                       10.000000 0.000000)
+            POINT(10.000000 6.000000)
+            LINESTRING(14.000000 4.000000,
+                       14.000000 2.000000,
+                       14.000000 0.000000)
+
+            >>> test_vect.find_by_point.geo(point=Point(20,20), maxdist=0)
+
+            >>> test_vect.close()
         """
         """
         feature_id = libvect.Vect_find_line(self.c_mapinfo,
         feature_id = libvect.Vect_find_line(self.c_mapinfo,
                                             point.x, point.y,
                                             point.x, point.y,
@@ -101,9 +160,79 @@ class PointFinder(AbstractFinder):
 
 
     @must_be_open
     @must_be_open
     def geos(self, point, maxdist, type='all', exclude=None):
     def geos(self, point, maxdist, type='all', exclude=None):
-        """Find the nearest line. Vect_find_line_list
-
-        Valid type are all the keys in find.vtype dictionary
+        """Find the nearest vector features around a specific point.
+
+            :param point: The point to search
+            :type point: grass.pygrass.vector.geometry.Point
+
+            :param maxdist: The maximum search distance around the point
+            :type maxdist: float
+
+            :param type: The type of feature to search for
+                         Valid type are all the keys in find.vtype dictionary
+            :type type: string
+
+            :param exclude: if > 0 number of lines which should be
+                            excluded from selection
+
+            :return: A list of grass.pygrass.vector.geometry
+                     (Line, Point, Boundary, Centroid) if found or None
+
+            This methods uses libvect.Vect_find_line_list()()
+
+            Examples:
+
+            >>> from grass.pygrass.vector import VectorTopo
+            >>> from grass.pygrass.vector.geometry import Point
+            >>> test_vect = VectorTopo(test_vector_name)
+            >>> test_vect.open('r')
+
+            # Find multiple features
+            >>> points = (Point(10,0), Point(10,5), Point(14,2))
+            >>> result = []
+            >>> for point in points:
+            ...     f = test_vect.find_by_point.geos(point=point,
+            ...                                      maxdist=1.5)
+            ...     if f:
+            ...         result.append(f)
+            >>> for f in result:
+            ...     print(f)             #doctest: +NORMALIZE_WHITESPACE
+            [Line([Point(10.000000, 4.000000),
+                   Point(10.000000, 2.000000),
+                   Point(10.000000, 0.000000)])]
+            [Line([Point(10.000000, 4.000000),
+                   Point(10.000000, 2.000000),
+                   Point(10.000000, 0.000000)]),
+             Point(10.000000, 6.000000)]
+            [Line([Point(14.000000, 4.000000),
+                   Point(14.000000, 2.000000),
+                   Point(14.000000, 0.000000)])]
+
+            # Find multiple boundaries
+            >>> point = Point(3,3)
+            >>> result = test_vect.find_by_point.geos(point=Point(3,3),
+            ...                                          type="boundary",
+            ...                                          maxdist=1.5)
+            >>> result                   #doctest: +NORMALIZE_WHITESPACE
+            [Boundary([Point(0.000000, 4.000000), Point(4.000000, 4.000000)]),
+             Boundary([Point(4.000000, 4.000000), Point(4.000000, 0.000000)]),
+             Boundary([Point(1.000000, 1.000000), Point(1.000000, 3.000000),
+                       Point(3.000000, 3.000000), Point(3.000000, 1.000000),
+                       Point(1.000000, 1.000000)]),
+             Boundary([Point(4.000000, 4.000000), Point(6.000000, 4.000000)])]
+
+            # Find multiple centroids
+            >>> point = Point(3,3)
+            >>> result = test_vect.find_by_point.geos(point=Point(3,3),
+            ...                                          type="centroid",
+            ...                                          maxdist=1.5)
+            >>> result                   #doctest: +NORMALIZE_WHITESPACE
+            [Centoid(2.500000, 2.500000),
+             Centoid(3.500000, 3.500000)]
+
+            >>> test_vect.find_by_point.geos(point=Point(20,20), maxdist=0)
+
+            >>> test_vect.close()
         """
         """
         excl = Ilist(exclude) if exclude else Ilist([])
         excl = Ilist(exclude) if exclude else Ilist([])
         found = Ilist()
         found = Ilist()
@@ -115,12 +244,47 @@ class PointFinder(AbstractFinder):
                                        excl.c_ilist, found.c_ilist):
                                        excl.c_ilist, found.c_ilist):
             return [read_line(f_id, self.c_mapinfo, self.table, self.writeable)
             return [read_line(f_id, self.c_mapinfo, self.table, self.writeable)
                     for f_id in found]
                     for f_id in found]
-        else:
-            return []
+
 
 
     @must_be_open
     @must_be_open
     def area(self, point):
     def area(self, point):
-        """Find the nearest area. Vect_find_area"""
+        """Find the nearest area around a specific point.
+
+            :param point: The point to search
+            :type point: grass.pygrass.vector.geometry.Point
+
+            :return: A grass.pygrass.vector.geometry.Area if found or None
+
+            This methods uses libvect.Vect_find_area()
+
+            Examples:
+
+            >>> from grass.pygrass.vector import VectorTopo
+            >>> from grass.pygrass.vector.geometry import Point
+            >>> test_vect = VectorTopo(test_vector_name)
+            >>> test_vect.open('r')
+
+            # Find AREAS
+            >>> points = (Point(0.5,0.5), Point(5,1), Point(7,1))
+            >>> result = []
+            >>> for point in points:
+            ...     area = test_vect.find_by_point.area(point)
+            ...     result.append(area)
+            >>> result
+            [Area(1), Area(2), Area(4)]
+            >>> for area in result:
+            ...     print(area.to_wkt())         #doctest: +NORMALIZE_WHITESPACE
+            Polygon((0.000000 0.000000, 0.000000 4.000000, 4.000000 4.000000,
+                     4.000000 0.000000, 0.000000 0.000000))
+            Polygon((4.000000 0.000000, 4.000000 4.000000, 6.000000 4.000000,
+                     6.000000 0.000000, 4.000000 0.000000))
+            Polygon((6.000000 0.000000, 6.000000 4.000000, 8.000000 4.000000,
+                     8.000000 0.000000, 6.000000 0.000000))
+
+            >>> test_vect.find_by_point.area(Point(20,20))
+
+            >>> test_vect.close()
+        """
         area_id = libvect.Vect_find_area(self.c_mapinfo, point.x, point.y)
         area_id = libvect.Vect_find_area(self.c_mapinfo, point.x, point.y)
         if area_id:
         if area_id:
             return Area(v_id=area_id, c_mapinfo=self.c_mapinfo,
             return Area(v_id=area_id, c_mapinfo=self.c_mapinfo,
@@ -128,7 +292,42 @@ class PointFinder(AbstractFinder):
 
 
     @must_be_open
     @must_be_open
     def island(self, point):
     def island(self, point):
-        """Find the nearest island. Vect_find_island"""
+        """Find the nearest island around a specific point.
+
+            :param point: The point to search
+            :type point: grass.pygrass.vector.geometry.Point
+
+            :return: A grass.pygrass.vector.geometry.Isle if found or None
+
+            This methods uses Vect_find_island.Vect_find_area()
+
+            Examples:
+
+            >>> from grass.pygrass.vector import VectorTopo
+            >>> from grass.pygrass.vector.geometry import Point
+            >>> test_vect = VectorTopo(test_vector_name)
+            >>> test_vect.open('r')
+
+            # Find ISLANDS
+            >>> points = (Point(2,2), Point(5,1))
+            >>> result = []
+            >>> for point in points:
+            ...     area = test_vect.find_by_point.island(point)
+            ...     result.append(area)
+            >>> result
+            [Isle(2), Isle(1)]
+            >>> for isle in result:
+            ...     print(isle.to_wkt())         #doctest: +NORMALIZE_WHITESPACE
+            Polygon((1.000000 1.000000, 3.000000 1.000000,
+                     3.000000 3.000000, 1.000000 3.000000, 1.000000 1.000000))
+            Polygon((0.000000 4.000000, 0.000000 0.000000, 4.000000 0.000000,
+                     6.000000 0.000000, 8.000000 0.000000, 8.000000 4.000000,
+                     6.000000 4.000000, 4.000000 4.000000, 0.000000 4.000000))
+
+            >>> test_vect.find_by_point.island(Point(20,20))
+
+            >>> test_vect.close()
+        """
         isle_id = libvect.Vect_find_island(self.c_mapinfo, point.x, point.y)
         isle_id = libvect.Vect_find_island(self.c_mapinfo, point.x, point.y)
         if isle_id:
         if isle_id:
             return Isle(v_id=isle_id, c_mapinfo=self.c_mapinfo,
             return Isle(v_id=isle_id, c_mapinfo=self.c_mapinfo,
@@ -136,62 +335,257 @@ class PointFinder(AbstractFinder):
 
 
 
 
 class BboxFinder(AbstractFinder):
 class BboxFinder(AbstractFinder):
+    """Bounding Box finder
+
+    This class provides an interface to search geometry features
+    of a vector map that are inside or intersect a boundingbox.
+    The BboxFinder class
+    is part of a topological vector map object.
+
+    """
     def __init__(self, c_mapinfo, table=None, writeable=False):
     def __init__(self, c_mapinfo, table=None, writeable=False):
+        """Find geometry feature(s)that are insider or intersect
+           with a boundingbox.
+
+            :param c_mapinfo: Pointer to the vector layer mapinfo structure
+            :type c_mapinfo: ctypes pointer to mapinfo structure
+
+            :param table: Attribute table of the vector layer
+            :type table: Class Table from grass.pygrass.table
+
+            :param writable: True or False
+            :type writeable: boolean
+        """
         super(BboxFinder, self).__init__(c_mapinfo, table, writeable)
         super(BboxFinder, self).__init__(c_mapinfo, table, writeable)
 
 
     @must_be_open
     @must_be_open
-    def geos(self, bbox, type='all', bbox_list=False):
-        """Find the geometry features contained in the bbox.
-        Vect_select_lines_by_box
-
-        Valid type are all the keys in find.vtype dictionary
+    def geos(self, bbox, type='all', bboxlist_only=False):
+        """Find the nearest vector features around a specific point.
+
+            :param bbox: The boundingbox to search in
+            :type bbox: grass.pygrass.vector.basic.Bbox
+
+            :param type: The type of feature to search for
+                         Valid type are all the keys in find.vtype dictionary
+            :type type: string
+
+            :param bboxlist_only: If true the BoxList will be returned,
+                                  no features are generated
+            :type bboxlist_only: boolean
+
+            :return: A list of grass.pygrass.vector.geometry
+                     (Line, Point, Boundary, Centroid) if found,
+                     or None if nothing was found.
+                     If bboxlist_only is True a BoxList
+                     object will be returned, or None if nothing was found.
+
+            This methods uses libvect.Vect_select_lines_by_box()
+
+            Examples:
+
+            >>> from grass.pygrass.vector import VectorTopo
+            >>> from grass.pygrass.vector.basic import Bbox
+            >>> test_vect = VectorTopo(test_vector_name)
+            >>> test_vect.open('r')
+
+            >>> bbox = Bbox(north=5, south=-1, east=3, west=-1)
+            >>> result = test_vect.find_by_bbox.geos(bbox=bbox)
+            >>> result                   #doctest: +NORMALIZE_WHITESPACE
+            [Boundary([Point(4.000000, 0.000000), Point(0.000000, 0.000000)]),
+             Boundary([Point(0.000000, 0.000000), Point(0.000000, 4.000000)]),
+             Boundary([Point(0.000000, 4.000000), Point(4.000000, 4.000000)]),
+             Boundary([Point(1.000000, 1.000000), Point(1.000000, 3.000000),
+                       Point(3.000000, 3.000000), Point(3.000000, 1.000000),
+                       Point(1.000000, 1.000000)]),
+             Centoid(2.500000, 2.500000)]
+
+            >>> bbox = Bbox(north=5, south=-1, east=3, west=-1)
+            >>> result = test_vect.find_by_bbox.geos(bbox=bbox,
+            ...                                      bboxlist_only=True)
+            >>> result                   #doctest: +NORMALIZE_WHITESPACE
+            Boxlist([Bbox(0.0, 0.0, 4.0, 0.0),
+                     Bbox(4.0, 0.0, 0.0, 0.0),
+                     Bbox(4.0, 4.0, 4.0, 0.0),
+                     Bbox(3.0, 1.0, 3.0, 1.0),
+                     Bbox(2.5, 2.5, 2.5, 2.5)])
+
+            >>> bbox = Bbox(north=7, south=-1, east=15, west=9)
+            >>> result = test_vect.find_by_bbox.geos(bbox=bbox)
+            >>> result                   #doctest: +NORMALIZE_WHITESPACE
+            [Line([Point(10.000000, 4.000000), Point(10.000000, 2.000000),
+                   Point(10.000000, 0.000000)]),
+             Point(10.000000, 6.000000),
+             Line([Point(12.000000, 4.000000), Point(12.000000, 2.000000),
+                   Point(12.000000, 0.000000)]),
+             Point(12.000000, 6.000000),
+             Line([Point(14.000000, 4.000000), Point(14.000000, 2.000000),
+                   Point(14.000000, 0.000000)]),
+             Point(14.000000, 6.000000)]
+
+            >>> bbox = Bbox(north=20, south=18, east=20, west=18)
+            >>> test_vect.find_by_bbox.geos(bbox=bbox)
+
+            >>> bbox = Bbox(north=20, south=18, east=20, west=18)
+            >>> test_vect.find_by_bbox.geos(bbox=bbox, bboxlist_only=True)
+
+            >>> test_vect.close()
         """
         """
         found = BoxList()
         found = BoxList()
         if libvect.Vect_select_lines_by_box(self.c_mapinfo, bbox.c_bbox,
         if libvect.Vect_select_lines_by_box(self.c_mapinfo, bbox.c_bbox,
                                             self.vtype[type], found.c_boxlist):
                                             self.vtype[type], found.c_boxlist):
-            if bbox_list:
+            if bboxlist_only:
                 return found
                 return found
             else:
             else:
-                return (read_line(f_id, self.c_mapinfo, self.table,
-                                  self.writeable) for f_id in found.ids)
+                return [read_line(f_id, self.c_mapinfo, self.table,
+                                  self.writeable) for f_id in found.ids]
 
 
     @must_be_open
     @must_be_open
     def nodes(self, bbox):
     def nodes(self, bbox):
-        """Find the nearest area. Vect_find_area"""
+        """Find the nodes inside a boundingbox.
+
+            :param bbox: The boundingbox to search in
+            :type bbox: grass.pygrass.vector.basic.Bbox
+
+            :return: A list of nodes or None if nothing was found
+
+            This methods uses libvect.Vect_select_nodes_by_box()
+
+            Examples:
+
+            >>> from grass.pygrass.vector import VectorTopo
+            >>> from grass.pygrass.vector.basic import Bbox
+            >>> test_vect = VectorTopo(test_vector_name)
+            >>> test_vect.open('r')
+
+            # Find nodes in box
+            >>> bbox = Bbox(north=5, south=-1, east=15, west=9)
+            >>> result = test_vect.find_by_bbox.nodes(bbox=bbox)
+            >>> result
+            [Node(2), Node(1), Node(4), Node(3), Node(5), Node(6)]
+
+            >>> bbox = Bbox(north=20, south=18, east=20, west=18)
+            >>> test_vect.find_by_bbox.nodes(bbox=bbox)
+
+            >>> test_vect.close()
+        """
         found = Ilist()
         found = Ilist()
         if libvect.Vect_select_nodes_by_box(self.c_mapinfo, bbox.c_bbox,
         if libvect.Vect_select_nodes_by_box(self.c_mapinfo, bbox.c_bbox,
                                             found.c_ilist):
                                             found.c_ilist):
-            for n_id in found:
-                yield Node(v_id=n_id, c_mapinfo=self.c_mapinfo,
-                           table=self.table, writeable=self.writeable)
+            if len(found) > 0:
+                return [Node(v_id=n_id, c_mapinfo=self.c_mapinfo,
+                             table=self.table, writeable=self.writeable)
+                        for n_id in found]
 
 
     @must_be_open
     @must_be_open
     def areas(self, bbox, boxlist=None, bboxlist_only=False):
     def areas(self, bbox, boxlist=None, bboxlist_only=False):
-        """Find the nearest area. Vect_find_area"""
+        """Find the areas inside a boundingbox.
+
+            :param bbox: The boundingbox to search in
+            :type bbox: grass.pygrass.vector.basic.Bbox
+
+            :param boxlist: An existing BoxList to be filled with
+            :type_boxlist: grass.pygrass.vector.basic.BoxList
+
+            :param bboxlist_only: If true the BoxList will be returned,
+                                  no features are generated
+            :type bboxlist_only: boolean
+
+            :return: A list of areas or None if nothing was found
+
+            This methods uses libvect.Vect_select_areas_by_box()
+
+            Examples:
+
+            >>> from grass.pygrass.vector import VectorTopo
+            >>> from grass.pygrass.vector.basic import Bbox
+            >>> test_vect = VectorTopo(test_vector_name)
+            >>> test_vect.open('r')
+
+            # Find areas in box
+            >>> bbox = Bbox(north=5, south=-1, east=9, west=-1)
+            >>> result = test_vect.find_by_bbox.areas(bbox=bbox)
+            >>> result
+            [Area(1), Area(2), Area(3), Area(4)]
+
+            >>> bbox = Bbox(north=5, south=-1, east=9, west=-1)
+            >>> result = test_vect.find_by_bbox.areas(bbox=bbox,
+            ...                                       bboxlist_only=True)
+            >>> result                   #doctest: +NORMALIZE_WHITESPACE
+            Boxlist([Bbox(4.0, 0.0, 4.0, 0.0),
+                     Bbox(4.0, 0.0, 6.0, 4.0),
+                     Bbox(3.0, 1.0, 3.0, 1.0),
+                     Bbox(4.0, 0.0, 8.0, 6.0)])
+
+            >>> bbox = Bbox(north=20, south=18, east=20, west=18)
+            >>> test_vect.find_by_bbox.areas(bbox=bbox)
+
+            >>> test_vect.find_by_bbox.areas(bbox=bbox,
+            ...                              bboxlist_only=True)
+
+            >>> test_vect.close()
+        """
         boxlist = boxlist if boxlist else BoxList()
         boxlist = boxlist if boxlist else BoxList()
         if libvect.Vect_select_areas_by_box(self.c_mapinfo, bbox.c_bbox,
         if libvect.Vect_select_areas_by_box(self.c_mapinfo, bbox.c_bbox,
                                             boxlist.c_boxlist):
                                             boxlist.c_boxlist):
             if bboxlist_only:
             if bboxlist_only:
                 return boxlist
                 return boxlist
             else:
             else:
-                return (Area(v_id=a_id, c_mapinfo=self.c_mapinfo,
+                return [Area(v_id=a_id, c_mapinfo=self.c_mapinfo,
                              table=self.table, writeable=self.writeable)
                              table=self.table, writeable=self.writeable)
-                        for a_id in boxlist.ids)
-        return []
+                        for a_id in boxlist.ids]
 
 
     @must_be_open
     @must_be_open
-    def islands(self, bbox, bbox_list=False):
-        """Find the nearest island. Vect_find_island"""
+    def islands(self, bbox, bboxlist_only=False):
+        """Find the isles inside a boundingbox.
+
+            :param bbox: The boundingbox to search in
+            :type bbox: grass.pygrass.vector.basic.Bbox
+
+            :param bboxlist_only: If true the BoxList will be returned,
+                                  no features are generated
+            :type bboxlist_only: boolean
+
+            :return: A list of isles or None if nothing was found
+
+            This methods uses libvect.Vect_select_isles_by_box()
+
+            Examples:
+
+            >>> from grass.pygrass.vector import VectorTopo
+            >>> from grass.pygrass.vector.basic import Bbox
+            >>> test_vect = VectorTopo(test_vector_name)
+            >>> test_vect.open('r')
+
+            # Find isles in box
+            >>> bbox = Bbox(north=5, south=-1, east=9, west=-1)
+            >>> result = test_vect.find_by_bbox.islands(bbox=bbox)
+            >>> result
+            [Isle(1), Isle(2)]
+
+            >>> bbox = Bbox(north=5, south=-1, east=9, west=-1)
+            >>> result = test_vect.find_by_bbox.islands(bbox=bbox,
+            ...                                       bboxlist_only=True)
+            >>> result                   #doctest: +NORMALIZE_WHITESPACE
+            Boxlist([Bbox(4.0, 0.0, 8.0, 0.0),
+                     Bbox(3.0, 1.0, 3.0, 1.0)])
+
+            >>> bbox = Bbox(north=20, south=18, east=20, west=18)
+            >>> test_vect.find_by_bbox.islands(bbox=bbox)
+
+            >>> test_vect.find_by_bbox.islands(bbox=bbox,
+            ...                              bboxlist_only=True)
+
+            >>> test_vect.close()
+        """
         found = BoxList()
         found = BoxList()
         if libvect.Vect_select_isles_by_box(self.c_mapinfo, bbox.c_bbox,
         if libvect.Vect_select_isles_by_box(self.c_mapinfo, bbox.c_bbox,
                                             found.c_boxlist):
                                             found.c_boxlist):
-            if bbox_list:
+            if bboxlist_only:
                 return found
                 return found
             else:
             else:
-                return (Isle(v_id=i_id, c_mapinfo=self.c_mapinfo,
+                return [Isle(v_id=i_id, c_mapinfo=self.c_mapinfo,
                              table=self.table, writeable=self.writeable)
                              table=self.table, writeable=self.writeable)
-                        for i_id in found.ids)
-        return []
+                        for i_id in found.ids]
 
 
 
 
 class PolygonFinder(AbstractFinder):
 class PolygonFinder(AbstractFinder):

+ 4 - 3
lib/python/pygrass/vector/testsuite/test_doctests.py

@@ -31,17 +31,18 @@ def load_tests(loader, tests, ignore):
     # TODO: ultimate solution is not to use _ as a buildin in lib/python
     # TODO: ultimate solution is not to use _ as a buildin in lib/python
     # for now it is the only place where it works
     # for now it is the only place where it works
     grass.gunittest.utils.do_doctest_gettext_workaround()
     grass.gunittest.utils.do_doctest_gettext_workaround()
-    
+
     from grass.pygrass import utils
     from grass.pygrass import utils
     utils.create_test_vector_map(gvector.test_vector_name)
     utils.create_test_vector_map(gvector.test_vector_name)
     utils.create_test_vector_map(gvector.abstract.test_vector_name)
     utils.create_test_vector_map(gvector.abstract.test_vector_name)
     utils.create_test_vector_map(gvector.geometry.test_vector_name)
     utils.create_test_vector_map(gvector.geometry.test_vector_name)
-    
+    utils.create_test_vector_map(gvector.find.test_vector_name)
+
     # this should be called at some top level
     # this should be called at some top level
     tests.addTests(doctest.DocTestSuite(gvector))
     tests.addTests(doctest.DocTestSuite(gvector))
     tests.addTests(doctest.DocTestSuite(gvector.abstract))
     tests.addTests(doctest.DocTestSuite(gvector.abstract))
     tests.addTests(doctest.DocTestSuite(gvector.basic))
     tests.addTests(doctest.DocTestSuite(gvector.basic))
-    #tests.addTests(doctest.DocTestSuite(gvector.find))
+    tests.addTests(doctest.DocTestSuite(gvector.find))
     tests.addTests(doctest.DocTestSuite(gvector.geometry))
     tests.addTests(doctest.DocTestSuite(gvector.geometry))
     tests.addTests(doctest.DocTestSuite(gvector.sql))
     tests.addTests(doctest.DocTestSuite(gvector.sql))
     #tests.addTests(doctest.DocTestSuite(gvector.table))
     #tests.addTests(doctest.DocTestSuite(gvector.table))

+ 18 - 16
lib/python/pygrass/vector/testsuite/test_geometry.py

@@ -94,10 +94,10 @@ class LineTestCase(TestCase):
 
 
     @classmethod
     @classmethod
     def setUpClass(cls):
     def setUpClass(cls):
-        
+
         from grass.pygrass import utils
         from grass.pygrass import utils
         utils.create_test_vector_map(cls.tmpname)
         utils.create_test_vector_map(cls.tmpname)
-        
+
         cls.vect = None
         cls.vect = None
         cls.vect = VectorTopo(cls.tmpname)
         cls.vect = VectorTopo(cls.tmpname)
         cls.vect.open('r')
         cls.vect.open('r')
@@ -172,15 +172,16 @@ class LineTestCase(TestCase):
             self.assertTupleEqual((5, 6), nodes2tuple(vect[6].nodes()))
             self.assertTupleEqual((5, 6), nodes2tuple(vect[6].nodes()))
 
 
 class NodeTestCase(TestCase):
 class NodeTestCase(TestCase):
-    
+
     tmpname = "NodeTestCase_map"
     tmpname = "NodeTestCase_map"
 
 
     @classmethod
     @classmethod
     def setUpClass(cls):
     def setUpClass(cls):
-        
+
+        # Tests are based on a stream network
         from grass.pygrass import utils
         from grass.pygrass import utils
-        utils.create_test_vector_map(cls.tmpname)
-        
+        utils.create_test_stream_network_map(cls.tmpname)
+
         cls.vect = None
         cls.vect = None
         cls.vect = VectorTopo(cls.tmpname)
         cls.vect = VectorTopo(cls.tmpname)
         cls.vect.open('r')
         cls.vect.open('r')
@@ -203,26 +204,27 @@ class NodeTestCase(TestCase):
         node = Node(v_id=4, c_mapinfo=self.c_mapinfo)
         node = Node(v_id=4, c_mapinfo=self.c_mapinfo)
         self.assertEqual(4, node.id)
         self.assertEqual(4, node.id)
         self.assertTrue(node.is2D)
         self.assertTrue(node.is2D)
-        self.assertEqual(1, node.nlines)
+        self.assertEqual(5, node.nlines)
 
 
     def test_coords(self):
     def test_coords(self):
         """Test Node coordinates"""
         """Test Node coordinates"""
         node = Node(v_id=4, c_mapinfo=self.c_mapinfo)
         node = Node(v_id=4, c_mapinfo=self.c_mapinfo)
-        self.assertTupleEqual((12.0, 0.0),
-                              node.coords())
+        self.assertTupleEqual((1.0, 0.0), node.coords())
 
 
     def test_ilines(self):
     def test_ilines(self):
-        """Test Node coordinates"""
-        node = Node(v_id=4, c_mapinfo=self.c_mapinfo) # Line 5 ends in this node
-        self.assertTupleEqual((-5,), tuple(node.ilines())) 
-        self.assertTupleEqual((-5,), tuple(node.ilines(only_in=True)))
-        node = Node(v_id=3, c_mapinfo=self.c_mapinfo) # Line 5 starts at this node
-        self.assertTupleEqual((5,), tuple(node.ilines(only_out=True)))
+        """Test Node neighbors"""
+        node = Node(v_id=4, c_mapinfo=self.c_mapinfo)
+        self.assertTupleEqual((6, -4, 7, -3, -5), tuple(node.ilines()))
+        self.assertTupleEqual((-4, -3, -5), tuple(node.ilines(only_in=True)))
+        node = Node(v_id=4, c_mapinfo=self.c_mapinfo)
+        self.assertTupleEqual((6, 7), tuple(node.ilines(only_out=True)))
 
 
     def test_angles(self):
     def test_angles(self):
         """Test Node angles"""
         """Test Node angles"""
         node = Node(v_id=4, c_mapinfo=self.c_mapinfo)
         node = Node(v_id=4, c_mapinfo=self.c_mapinfo)
-        angles = (1.5707963705062866,) # 90°
+        angles = (-1.5707963705062866, 0.7853981852531433,
+                   1.2793395519256592, 1.8622530698776245,
+                   2.356194496154785)
         self.assertTupleEqual(angles, tuple(node.angles()))
         self.assertTupleEqual(angles, tuple(node.angles()))
 
 
 if __name__ == '__main__':
 if __name__ == '__main__':