Opened 6 years ago

Closed 6 years ago

#2320 closed defect (fixed)

PyGRASS doesn't write 3D vector map

Reported by: annakrat Owned by: grass-dev@…
Priority: normal Milestone: 7.0.0
Component: Python Version: svn-trunk
Keywords: pygrass Cc:
CPU: Unspecified Platform: All

Description

When I create a new vector using PyGRASS, create 3D points and write them to the map, v.info says the map is 2D. The problem is that PyGRASS doesn't specify anywhere that the map should be 3D. The following change works for me but I am not completely sure it's correct:

Index: pygrass/vector/__init__.py
===================================================================
--- pygrass/vector/__init__.py	(revision 60631)
+++ pygrass/vector/__init__.py	(working copy)
@@ -187,6 +187,12 @@
 
         if geo_obj.gtype == _Area.gtype:
             result = self._write_area(geo_obj)
+
+        if not geo_obj.is2D:
+            self.c_mapinfo.contents.head.with_z = 1
+            self.c_mapinfo.contents.plus.with_z = 1
+            self.c_mapinfo.contents.plus.spidx_with_z = 1
+
         result = libvect.Vect_write_line(self.c_mapinfo, geo_obj.gtype,
                                          geo_obj.c_points, geo_obj.c_cats)
         if result == -1:

Change History (4)

comment:1 Changed 6 years ago by zarch

Thanks to look into it!

I have 2 doubts:

  • I'm not sure if it is correct to silently switch the vector map from 2D to 3D when the user try to write a geometry feature. Maybe we should move the patch from the write method to open (in abstract/Info), in this way we don't have to check if the geo_obj.is2D for each call to the writing method and user have to open the vector map explicity with 3D enabled. So user could write something like:
with VectorTopo("new3D", mode="w", is2D=False) as vect:
    vect.write(Point(10, 20, 100))

Actually I don't like too much the is2D parameter in the open method, perhaps is3D could be clearer, but we should change the attribute of the geometry features from is2D to is3D for consistency.

  • Do you know if there is a function in the GRASS API to enable 3D on vector map instead of directly modifying the c_mapinfo structure? If not your approach it looks fine to me.

comment:2 in reply to:  1 ; Changed 6 years ago by annakrat

Replying to zarch:

Thanks to look into it!

I have 2 doubts:

  • I'm not sure if it is correct to silently switch the vector map from 2D to 3D when the user try to write a geometry feature. Maybe we should move the patch from the write method to open (in abstract/Info), in this way we don't have to check if the geo_obj.is2D for each call to the writing method and user have to open the vector map explicity with 3D enabled. So user could write something like:
with VectorTopo("new3D", mode="w", is2D=False) as vect:
    vect.write(Point(10, 20, 100))

Yes, that's much better.

Actually I don't like too much the is2D parameter in the open method, perhaps is3D could be clearer, but we should change the attribute of the geometry features from is2D to is3D for consistency.

Yes, I definitely agree, is3D would be much more intuitive.

  • Do you know if there is a function in the GRASS API to enable 3D on vector map instead of directly modifying the c_mapinfo structure? If not your approach it looks fine to me.

Probably we don't need to change 2D/3D, user specifies 3D when opening the vector map and there is already a parameter for that in Vect_open_new.

See also the other ticket (#2311) which deals with reading 3D points from a vector map.

comment:3 in reply to:  2 Changed 6 years ago by zarch

Replying to annakrat:

Actually I don't like too much the is2D parameter in the open method, perhaps is3D could be clearer, but we should change the attribute of the geometry features from is2D to is3D for consistency.

Yes, I definitely agree, is3D would be much more intuitive.

I didn't change that part for now...

Probably we don't need to change 2D/3D, user specifies 3D when opening the vector map and there is already a parameter for that in Vect_open_new.

ok, done.

Now you should be able to create a 3D vector map with:

with VectorTopo("new3D", mode="w", with_z=True) as vect:
    vect.write(Point(10, 20, 100))

or using the with_z parameter with the open method:

vect = VectorTopo("new3D")
vect.open(mode="w", with_z=True)
vect.write(Point(10, 20, 100))
vect.close()

I did some tests and it seems to work, let me know if you have problems.

comment:4 Changed 6 years ago by annakrat

Resolution: fixed
Status: newclosed

Thanks a lot, it's working for me now.

Note: See TracTickets for help on using tickets.