[GRASS-SVN] r62034 - in grass/trunk/lib/python/pygrass/vector: . testsuite

svn_grass at osgeo.org svn_grass at osgeo.org
Thu Sep 18 03:09:47 PDT 2014


Author: zarch
Date: 2014-09-18 03:09:46 -0700 (Thu, 18 Sep 2014)
New Revision: 62034

Modified:
   grass/trunk/lib/python/pygrass/vector/__init__.py
   grass/trunk/lib/python/pygrass/vector/find.py
   grass/trunk/lib/python/pygrass/vector/geometry.py
   grass/trunk/lib/python/pygrass/vector/testsuite/test_geometry.py
Log:
pygrass: Add Node topology class (contribution: Maurizio Cingi)

Modified: grass/trunk/lib/python/pygrass/vector/__init__.py
===================================================================
--- grass/trunk/lib/python/pygrass/vector/__init__.py	2014-09-18 03:51:49 UTC (rev 62033)
+++ grass/trunk/lib/python/pygrass/vector/__init__.py	2014-09-18 10:09:46 UTC (rev 62034)
@@ -28,7 +28,6 @@
           "islands": libvect.Vect_get_num_islands,
           "kernels": libvect.Vect_get_num_kernels,
           "lines": libvect.Vect_get_num_lines,
-          "points": libvect.Vect_get_num_line_points,
           "nodes": libvect.Vect_get_num_nodes,
           "updated_lines": libvect.Vect_get_num_updated_lines,
           "updated_nodes": libvect.Vect_get_num_updated_nodes,

Modified: grass/trunk/lib/python/pygrass/vector/find.py
===================================================================
--- grass/trunk/lib/python/pygrass/vector/find.py	2014-09-18 03:51:49 UTC (rev 62033)
+++ grass/trunk/lib/python/pygrass/vector/find.py	2014-09-18 10:09:46 UTC (rev 62034)
@@ -9,7 +9,7 @@
 from grass.pygrass.errors import must_be_open
 
 from grass.pygrass.vector.basic import Ilist, BoxList
-from grass.pygrass.vector.geometry import read_line, Isle, Area, Point
+from grass.pygrass.vector.geometry import read_line, Isle, Area, Point, Node
 
 
 class AbstractFinder(object):
@@ -160,8 +160,8 @@
         if libvect.Vect_select_nodes_by_box(self.c_mapinfo, bbox.c_bbox,
                                             found.c_ilist):
             for n_id in found:
-                yield Point(v_id=n_id, c_mapinfo=self.c_mapinfo,
-                            table=self.table, writable=self.writable)
+                yield Node(v_id=n_id, c_mapinfo=self.c_mapinfo,
+                           table=self.table, writable=self.writable)
 
     @must_be_open
     def areas(self, bbox, boxlist=None, bboxlist_only=False):

Modified: grass/trunk/lib/python/pygrass/vector/geometry.py
===================================================================
--- grass/trunk/lib/python/pygrass/vector/geometry.py	2014-09-18 03:51:49 UTC (rev 62033)
+++ grass/trunk/lib/python/pygrass/vector/geometry.py	2014-09-18 10:09:46 UTC (rev 62034)
@@ -253,11 +253,12 @@
     """
     gtype = None
 
-    def __init__(self, v_id=None, c_mapinfo=None, c_points=None, c_cats=None,
+    def __init__(self, v_id=0, c_mapinfo=None, c_points=None, c_cats=None,
                  table=None, writable=False, is2D=True):
         self.id = v_id  # vector id
         self.c_mapinfo = c_mapinfo
-        self.is2D = is2D
+        self.is2D = (is2D if is2D is not None else
+                     bool(libvect.Vect_is_3d(self.c_mapinfo) != 1))
 
         read = False
         # set c_points
@@ -332,7 +333,7 @@
 
     def __init__(self, x=0, y=0, z=None, **kargs):
         super(Point, self).__init__(**kargs)
-        if self.id is not None:
+        if self.id and self.c_mapinfo:
             self.read()
         else:
             self.is2D = True if z is None else False
@@ -1060,11 +1061,76 @@
         """
         libvect.Vect_reset_line(self.c_points)
 
+    def nodes(self):
+        """Return the nodes in the line"""
+        if self.is_with_topology():
+            n1 = ctypes.c_int()
+            n2 = ctypes.c_int()
+            libvect.Vect_get_line_nodes(self.c_mapinfo, self.id,
+                                        ctypes.byref(n1),
+                                        ctypes.byref(n2))
+            return (Node(n1.value, self.c_mapinfo),
+                    Node(n2.value, self.c_mapinfo))
 
+
 class Node(object):
-    pass
+    def __init__(self, v_id, c_mapinfo):
+        self.id = v_id  # vector id
+        self.c_mapinfo = c_mapinfo
+        self.is2D = bool(libvect.Vect_is_3d(self.c_mapinfo) != 1)
+        self.nlines = libvect.Vect_get_node_n_lines(self.c_mapinfo, self.id)
 
+    def __len__(self):
+        return self.nlines
 
+    def __iter__(self):
+        return self.ilines()
+
+    def __repr__(self):
+        return "Node(%d)" % self.id
+
+    def coords(self):
+        """Return a tuple with the node coordinates."""
+        x = ctypes.c_double()
+        y = ctypes.c_double()
+        z = ctypes.c_double()
+        libvect.Vect_get_node_coor(self.c_mapinfo, self.id, ctypes.byref(x),
+                                   ctypes.byref(y), ctypes.byref(z))
+        return (x.value, y.value) if self.is2D else (x.value, y.value, z.value)
+
+    def ilines(self, only_in=False, only_out=False):
+        """Return a generator with all lines id connected to a node.
+        The line id is negative if line is ending on the node and positive if
+        starting from the node.
+
+        :param only_in: Return only the lines that are ending in the node
+        :type only_in: bool
+        :param only_out: Return only the lines that are starting in the node
+        :type only_out: bool
+        """
+        for iline in range(self.nlines):
+            lid = libvect.Vect_get_node_line(self.c_mapinfo, self.id, iline)
+            if (not only_in and lid > 0) or (not only_out and lid < 0):
+                yield lid
+
+    def lines(self, only_in=False, only_out=False):
+        """Return a generator with all lines connected to a node.
+
+        :param only_in: Return only the lines that are ending in the node
+        :type only_in: bool
+        :param only_out: Return only the lines that are starting in the node
+        :type only_out: bool
+        """
+        for iline in self.ilines(only_in, only_out):
+            yield Line(id=abs(iline), c_mapinfo=self.c_mapinfo)
+
+    def angles(self):
+        """Return a generator with all lines angles in a node."""
+        for iline in range(self.nlines):
+            yield libvect.Vect_get_node_line_angle(self.c_mapinfo,
+                                                   self.id, iline)
+
+
 class Boundary(Line):
     """
     """

Modified: grass/trunk/lib/python/pygrass/vector/testsuite/test_geometry.py
===================================================================
--- grass/trunk/lib/python/pygrass/vector/testsuite/test_geometry.py	2014-09-18 03:51:49 UTC (rev 62033)
+++ grass/trunk/lib/python/pygrass/vector/testsuite/test_geometry.py	2014-09-18 10:09:46 UTC (rev 62034)
@@ -12,7 +12,8 @@
 
 import grass.lib.vector as libvect
 
-from grass.pygrass.vector.geometry import Point, Line
+from grass.pygrass.vector import VectorTopo
+from grass.pygrass.vector.geometry import Point, Line, Node
 
 
 class PointTestCase(TestCase):
@@ -124,9 +125,68 @@
         self.assertTupleEqual(line.get_pnt(1).coords(), vals)
 
     def test_bbox(self):
-        line = Line([(0, 0), (0, 1), (2, 1), (2, 0)])
+        """Test bbox method"""
+        line = Line([(0, 10), (0, 11), (1, 11), (1, 10)])
         bbox = line.bbox()
+        self.assertEqual(11, bbox.north)
+        self.assertEqual(10, bbox.south)
+        self.assertEqual(1, bbox.east)
+        self.assertEqual(0, bbox.west)
 
+    def test_nodes(self):
+        """Test inodes method"""
+        def nodes2tuple(nodes):
+            """Convert an iterable of nodes to a tuple of nodes id"""
+            return tuple(n.id for n in nodes)
 
+        with VectorTopo("roadsmajor", mode='r') as vect:
+            self.assertTupleEqual((206, 172), nodes2tuple(vect[284].nodes()))
+            self.assertTupleEqual((208, 206), nodes2tuple(vect[287].nodes()))
+            self.assertTupleEqual((206, 209), nodes2tuple(vect[288].nodes()))
+            self.assertTupleEqual((218, 206), nodes2tuple(vect[301].nodes()))
+
+
+
+class NodeTestCase(TestCase):
+    @classmethod
+    def setUpClass(cls):
+        cls.vect = None
+        cls.vect = VectorTopo("roadsmajor")
+        cls.vect.open('r')
+        cls.c_mapinfo = cls.vect.c_mapinfo
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.vect is not None:
+            cls.vect.close()
+            cls.c_mapinfo = None
+
+    def test_init(self):
+        """Test Node __init__"""
+        node = Node(v_id=206, c_mapinfo=self.c_mapinfo)
+        self.assertEqual(206, node.id)
+        self.assertTrue(node.is2D)
+        self.assertEqual(4, node.nlines)
+
+    def test_coords(self):
+        """Test Node coordinates"""
+        node = Node(v_id=206, c_mapinfo=self.c_mapinfo)
+        self.assertTupleEqual((620906.5786131569, 221685.65913128198),
+                              node.coords())
+
+    def test_ilines(self):
+        """Test Node coordinates"""
+        node = Node(v_id=206, c_mapinfo=self.c_mapinfo)
+        self.assertTupleEqual((288, -301, -287, 284), tuple(node.ilines()))
+        self.assertTupleEqual((-301, -287), tuple(node.ilines(only_in=True)))
+        self.assertTupleEqual((288, 284), tuple(node.ilines(only_out=True)))
+
+    def test_angles(self):
+        """Test Node angles"""
+        node = Node(v_id=206, c_mapinfo=self.c_mapinfo)
+        angles = (-3.044905185699463, -1.026218056678772,
+                  0.10362745821475983, 2.2236430644989014)
+        self.assertTupleEqual(angles, tuple(node.angles()))
+
 if __name__ == '__main__':
     test()



More information about the grass-commit mailing list