[GRASS-SVN] r58447 - grass/trunk/vector/v.out.ogr

svn_grass at osgeo.org svn_grass at osgeo.org
Wed Dec 11 15:22:40 PST 2013


Author: martinl
Date: 2013-12-11 15:22:40 -0800 (Wed, 11 Dec 2013)
New Revision: 58447

Added:
   grass/trunk/vector/v.out.ogr/export_areas.c
   grass/trunk/vector/v.out.ogr/export_lines.c
Modified:
   grass/trunk/vector/v.out.ogr/args.c
   grass/trunk/vector/v.out.ogr/attrb.c
   grass/trunk/vector/v.out.ogr/create.c
   grass/trunk/vector/v.out.ogr/local_proto.h
   grass/trunk/vector/v.out.ogr/main.c
   grass/trunk/vector/v.out.ogr/v.out.ogr.html
Log:
v.out.ogr: implement multi-feature support


Modified: grass/trunk/vector/v.out.ogr/args.c
===================================================================
--- grass/trunk/vector/v.out.ogr/args.c	2013-12-11 20:21:50 UTC (rev 58446)
+++ grass/trunk/vector/v.out.ogr/args.c	2013-12-11 23:22:40 UTC (rev 58447)
@@ -6,39 +6,30 @@
 		struct Options *options, struct Flags *flags)
 {
     options->input = G_define_standard_option(G_OPT_V_INPUT);
+    options->input->label = _("Name of input vector map to export");
+    
+    options->field = G_define_standard_option(G_OPT_V_FIELD);
+    options->field->guisection = _("Selection");
 
     options->type = G_define_standard_option(G_OPT_V3_TYPE);
     options->type->options =
 	"point,line,boundary,centroid,area,face,kernel,auto";
     options->type->answer = "auto";
-
     options->type->label = _("Feature type(s)");
     options->type->description =
 	_("Combination of types is not supported "
 	  "by all output formats. Default is to use first type found in input vector map.");
     options->type->guisection = _("Selection");
 
-    options->field = G_define_standard_option(G_OPT_V_FIELD);
-    options->field->guisection = _("Selection");
-
     options->dsn = G_define_option();
     options->dsn->key = "dsn";
     options->dsn->type = TYPE_STRING;
     options->dsn->required = YES;
-    options->dsn->label = _("OGR output datasource name");
+    options->dsn->label = _("Name of output OGR datasource");
     options->dsn->description =
-	_("For example: ESRI Shapefile: filename or directory for storage");
+	_("For example: ESRI Shapefile: filename or directory for storage\n"
+          "\tPostGIS database: connection string");
 
-    options->layer = G_define_option();
-    options->layer->key = "olayer";
-    options->layer->type = TYPE_STRING;
-    options->layer->required = NO;
-    options->layer->label =
-	_("OGR layer name. If not specified, input name is used.");
-    options->layer->description =
-	_("For example: ESRI Shapefile: shapefile name");
-    options->layer->guisection = _("Creation");
-
     options->format = G_define_option();
     options->format->key = "format";
     options->format->type = TYPE_STRING;
@@ -48,6 +39,28 @@
     options->format->options = OGR_list_write_drivers();
     options->format->description = _("Data format to write");
     
+    options->layer = G_define_option();
+    options->layer->key = "olayer";
+    options->layer->type = TYPE_STRING;
+    options->layer->required = NO;
+    options->layer->label =
+	_("Name for output OGR layer. If not specified, input name is used");
+    options->layer->description =
+	_("For example: ESRI Shapefile: shapefile name\n"
+          "\tPostGIS database: table name");
+    options->layer->guisection = _("Creation");
+
+    options->otype = G_define_standard_option(G_OPT_V_TYPE);
+    options->otype->key = "otype";
+    options->otype->options = "line,boundary";
+    options->otype->answer = "";
+    options->otype->description = _("Optionally change default output type");
+    G_asprintf((char **) &options->otype->descriptions,
+	       "line;%s;boundary;%s",
+	       _("export area boundaries as linestrings"),
+               _("export lines as polygons"));
+    options->otype->guisection = _("Creation");
+
     options->dsco = G_define_option();
     options->dsco->key = "dsco";
     options->dsco->type = TYPE_STRING;
@@ -70,7 +83,7 @@
 
     flags->update = G_define_flag();
     flags->update->key = 'u';
-    flags->update->description = _("Open an existing datasource for update");
+    flags->update->description = _("Open an existing OGR datasource for update");
 
     flags->append = G_define_flag();
     flags->append->key = 'a';
@@ -107,10 +120,16 @@
     flags->poly->description = _("Export lines as polygons");
     flags->poly->guisection = _("Creation");
 
+    flags->multi = G_define_flag();
+    flags->multi->key = 'm';
+    flags->multi->description =
+	_("Export vector data as multi-features");
+    flags->multi->guisection = _("Creation");
+
     flags->new = G_define_flag();
     flags->new->key = 'n';
     flags->new->description =
-	_("Create a new empty OGR layer in defined OGR datasource "
+	_("Create a new empty layer in defined OGR datasource "
 	  "and exit. Nothing is read from input.");
     flags->new->guisection = _("Creation");
     

Modified: grass/trunk/vector/v.out.ogr/attrb.c
===================================================================
--- grass/trunk/vector/v.out.ogr/attrb.c	2013-12-11 20:21:50 UTC (rev 58446)
+++ grass/trunk/vector/v.out.ogr/attrb.c	2013-12-11 23:22:40 UTC (rev 58447)
@@ -2,9 +2,9 @@
 
 #include "local_proto.h"
 
-int mk_att(int cat, struct field_info *Fi, dbDriver *Driver, int ncol,
+int mk_att(int cat, struct field_info *Fi, dbDriver *driver, int ncol,
 	   int *colctype, const char **colname, int doatt, int nocat,
-	   OGRFeatureH Ogr_feature, int *noatt, int *fout)
+	   OGRFeatureH Ogr_feature, int *noatt)
 {
     int j, ogrfieldnum;
     int more;
@@ -44,8 +44,7 @@
 	    sprintf(buf, "SELECT * FROM %s WHERE %s = %d", Fi->table, Fi->key, cat);
 	    G_debug(2, "SQL: %s", buf);
 	    db_set_string(&dbstring, buf);
-	    if (db_open_select_cursor
-			    (Driver, &dbstring, &cursor, DB_SEQUENTIAL) != DB_OK) {
+	    if (db_open_select_cursor (driver, &dbstring, &cursor, DB_SEQUENTIAL) != DB_OK) {
 		    G_fatal_error(_("Cannot select attributes for cat = %d"),
 		  cat);
 	    }
@@ -143,7 +142,6 @@
 	/* G_warning ("Line without cat of layer %d", field); */
 	nocat++;
     }
-    (*fout)++;
 
     /*
     db_free_string(&dbstring);

Modified: grass/trunk/vector/v.out.ogr/create.c
===================================================================
--- grass/trunk/vector/v.out.ogr/create.c	2013-12-11 20:21:50 UTC (rev 58446)
+++ grass/trunk/vector/v.out.ogr/create.c	2013-12-11 23:22:40 UTC (rev 58447)
@@ -36,3 +36,38 @@
 	G_fatal_error(_("Creation of OGR layer <%s> failed"), layer);
     }
 }
+
+OGRwkbGeometryType get_multi_wkbtype(OGRwkbGeometryType wkbtype)
+{
+    OGRwkbGeometryType multiwkbtype;
+
+    switch (wkbtype) {
+    case wkbPoint:
+        multiwkbtype = wkbMultiPoint;
+        break;
+    case wkbLineString:
+        multiwkbtype = wkbMultiLineString;
+        break;
+    case wkbPolygon:
+        multiwkbtype = wkbMultiPolygon;
+        break;
+    default:
+        multiwkbtype = wkbGeometryCollection;
+        break;
+    }
+
+    return multiwkbtype;
+}
+
+OGRwkbGeometryType get_wkbtype(int type, int otype)
+{
+    if (type == GV_POINT || type == GV_KERNEL ||
+        (type == GV_CENTROID && otype & GV_CENTROID))
+        return wkbPoint;
+    else if (type & GV_LINES)
+        return wkbLineString;
+    else if (type == GV_FACE)
+        return wkbPolygon25D;
+
+    return wkbGeometryCollection;
+}

Added: grass/trunk/vector/v.out.ogr/export_areas.c
===================================================================
--- grass/trunk/vector/v.out.ogr/export_areas.c	                        (rev 0)
+++ grass/trunk/vector/v.out.ogr/export_areas.c	2013-12-11 23:22:40 UTC (rev 58447)
@@ -0,0 +1,307 @@
+#include <grass/glocale.h>
+
+#include "local_proto.h"
+
+static int export_areas_single(struct Map_info *, int, int, 
+                               OGRFeatureDefnH, OGRLayerH,
+                               struct field_info *, dbDriver *, int, int *, 
+                               const char **, int, int,
+                               int *, int *);
+static int export_areas_multi(struct Map_info *, int, int, 
+                              OGRFeatureDefnH, OGRLayerH,
+                              struct field_info *, dbDriver *, int, int *, 
+                              const char **, int, int,
+                              int *, int *);
+static OGRGeometryH create_polygon(struct Map_info *, int, struct line_pnts *);
+
+/* export areas as single/multi-polygons */
+int export_areas(struct Map_info *In, int field, int multi, int donocat,
+                 OGRFeatureDefnH Ogr_featuredefn,OGRLayerH Ogr_layer,
+                 struct field_info *Fi, dbDriver *driver, int ncol, int *colctype,
+                 const char **colname, int doatt, int nocat,
+                 int *noatt, int *fout)
+{
+    if (multi)
+        /* export as multi-polygons */
+        return export_areas_multi(In, field, donocat,
+                                  Ogr_featuredefn, Ogr_layer,
+                                  Fi, driver, ncol, colctype, 
+                                  colname, doatt, nocat,
+                                  noatt, fout);
+    
+    /* export as polygons */
+    return export_areas_single(In, field, donocat,
+                               Ogr_featuredefn, Ogr_layer,
+                               Fi, driver, ncol, colctype, 
+                               colname, doatt, nocat,
+                               noatt, fout);
+}
+
+int export_areas_single(struct Map_info *In, int field, int donocat,
+                        OGRFeatureDefnH Ogr_featuredefn,OGRLayerH Ogr_layer,
+                        struct field_info *Fi, dbDriver *driver, int ncol, int *colctype,
+                        const char **colname, int doatt, int nocat,
+                        int *n_noatt, int *n_nocat)
+{
+    int i, j;
+    int centroid, cat, area, n_areas;
+    int n_exported;
+    
+    struct line_pnts *Points;
+    struct line_cats *Cats;
+
+    OGRGeometryH Ogr_geometry;
+    OGRFeatureH Ogr_feature;
+
+    Points = Vect_new_line_struct();
+    Cats = Vect_new_cats_struct();
+
+    n_exported = 0;
+
+    n_areas = Vect_get_num_areas(In);
+    for (i = 1; i <= n_areas; i++) {
+        G_percent(i, n_areas, 5);
+        
+        /* get centroid's category */
+        centroid = Vect_get_area_centroid(In, i);
+        cat = -1;
+        if (centroid > 0) {
+            Vect_read_line(In, NULL, Cats, centroid);
+            Vect_cat_get(Cats, field, &cat);
+        }
+        G_debug(3, "area = %d centroid = %d ncats = %d", i, centroid,
+                Cats->n_cats);
+        if (cat < 0 && !donocat) {
+            (*n_nocat)++;
+            continue; /* skip areas without category, do not export
+                       * not labeled */
+        }
+        
+        /* find correspoding area */
+        area = Vect_get_centroid_area(In, centroid);
+        if (area == 0)
+            continue;
+
+        /* create polygon from area */
+        Ogr_geometry = create_polygon(In, area, Points);
+
+        /* add feature */
+        Ogr_feature = OGR_F_Create(Ogr_featuredefn);
+        OGR_F_SetGeometry(Ogr_feature, Ogr_geometry);
+        
+        /* output one feature for each category */
+        for (j = -1; j < Cats->n_cats; j++) {
+            if (j == -1) {
+                if (cat >= 0)
+                    continue;	/* cat(s) exists */
+            }
+            else {
+                if (Cats->field[j] == field)
+                    cat = Cats->cat[j];
+                else
+                    continue;
+            }
+            
+            mk_att(cat, Fi, driver, ncol, colctype, colname, doatt, nocat,
+                   Ogr_feature, n_noatt);
+            OGR_L_CreateFeature(Ogr_layer, Ogr_feature);
+            
+            n_exported++;
+        }
+        OGR_G_DestroyGeometry(Ogr_geometry);
+        OGR_F_Destroy(Ogr_feature);
+    }
+
+    Vect_destroy_line_struct(Points);
+    Vect_destroy_cats_struct(Cats);
+
+    return n_exported;
+}
+
+int export_areas_multi(struct Map_info *In, int field, int donocat,
+                       OGRFeatureDefnH Ogr_featuredefn,OGRLayerH Ogr_layer,
+                       struct field_info *Fi, dbDriver *driver, int ncol, int *colctype,
+                       const char **colname, int doatt, int nocat,
+                       int *n_noatt, int *n_nocat)
+{
+    int i, n_exported, area;
+    int cat, lcat, ncats_field, line, type, findex, ipart;
+
+    struct line_pnts *Points;
+    struct line_cats *Cats;
+    struct ilist *cat_list, *line_list;
+
+    OGRGeometryH Ogr_geometry, Ogr_geometry_part;
+    OGRFeatureH Ogr_feature;
+    OGRwkbGeometryType wkbtype, wkbtype_part;
+    
+    Points = Vect_new_line_struct();
+    Cats = Vect_new_cats_struct();
+    cat_list = Vect_new_list();
+    line_list = Vect_new_list();
+
+    n_exported = 0;
+
+    /* check if category index is available for given field */
+    findex = Vect_cidx_get_field_index(In, field);
+    if (findex == -1)
+        G_fatal_error(_("Unable to export multi-features. No category index for layer %d."),
+                      field);
+    
+    /* determine type */
+    wkbtype_part = wkbPolygon;
+    wkbtype = get_multi_wkbtype(wkbtype_part);
+    
+    ncats_field = Vect_cidx_get_unique_cats_by_index(In, findex, cat_list);
+    G_debug(1, "n_cats = %d for layer %d", ncats_field, field);
+
+    for (i = 0; i < cat_list->n_values; i++) {
+        cat = cat_list->value[i];
+        /* find all centroids with given category */
+        Vect_cidx_find_all(In, field, GV_CENTROID, cat, line_list);
+
+        /* create multi-feature */
+        Ogr_geometry = OGR_G_CreateGeometry(wkbtype);
+
+        /* build simple features geometry, go through all parts */
+        for (ipart = 0; ipart < line_list->n_values; ipart++) {
+            line = line_list->value[ipart];
+            G_debug(3, "cat=%d, line=%d -> part=%d", cat, line, ipart);
+
+            /* get centroid's category */
+            Vect_read_line(In, NULL, Cats, line);
+            /* check for category consistency */
+            Vect_cat_get(Cats, field, &lcat);
+            if (lcat > 0 && lcat != cat)
+                G_fatal_error(_("Unable to create multi-feature. "
+                                "Invalid category %d (should be %d)"),
+                              lcat, cat);
+            
+            /* find correspoding area */
+            area = Vect_get_centroid_area(In, line);
+            if (area == 0)
+                continue;
+                
+            /* create polygon from area */
+            Ogr_geometry_part = create_polygon(In, area, Points);
+
+            /* add part */
+            OGR_G_AddGeometryDirectly(Ogr_geometry, Ogr_geometry_part);
+        }
+
+        if (!OGR_G_IsEmpty(Ogr_geometry)) {
+            /* write multi-feature */
+            Ogr_feature = OGR_F_Create(Ogr_featuredefn);
+            OGR_F_SetGeometry(Ogr_feature, Ogr_geometry);
+            
+            mk_att(cat, Fi, driver, ncol, colctype, colname, doatt, nocat,
+                   Ogr_feature, n_noatt);
+            OGR_L_CreateFeature(Ogr_layer, Ogr_feature);
+
+            OGR_F_Destroy(Ogr_feature);
+
+            n_exported++;
+        }
+        else {
+            /* skip empty features */
+            G_debug(3, "multi-feature is empty -> skipped");
+        }
+        
+        OGR_G_DestroyGeometry(Ogr_geometry);
+    }
+
+    /* check lines without category, if -c flag is given write them as
+     * one multi-feature */
+    Ogr_geometry = OGR_G_CreateGeometry(wkbtype);
+    
+    Vect_rewind(In);
+    Vect_set_constraint_type(In, GV_CENTROID);
+    while(TRUE) {
+        type = Vect_read_next_line(In, NULL, Cats);
+        if (type < 0)
+            break;
+
+        /* get centroid's category */
+        Vect_cat_get(Cats, field, &cat);
+        if (cat > 0)
+            continue; /* skip features with category */
+        if (cat < 0 && !donocat) {
+            (*n_nocat)++;
+            continue; /* skip lines without category, do not export
+                       * not labeled */
+        }
+
+        /* find correspoding area */
+        area = Vect_get_centroid_area(In, line);
+        if (area == 0)
+                continue;
+                
+        /* create polygon from area */
+        Ogr_geometry_part = create_polygon(In, area, Points);
+        
+        /* add part */
+        OGR_G_AddGeometryDirectly(Ogr_geometry, Ogr_geometry_part);
+    }
+
+    if (!OGR_G_IsEmpty(Ogr_geometry)) {
+        /* write multi-feature */
+        Ogr_feature = OGR_F_Create(Ogr_featuredefn);
+        OGR_F_SetGeometry(Ogr_feature, Ogr_geometry);
+        
+        mk_att(cat, Fi, driver, ncol, colctype, colname, doatt, nocat,
+               Ogr_feature, n_noatt);
+        OGR_L_CreateFeature(Ogr_layer, Ogr_feature);
+
+        OGR_F_Destroy(Ogr_feature);
+        
+        n_exported++;
+    }
+    else {
+        /* skip empty features */
+        G_debug(3, "multi-feature is empty -> skipped");
+    }
+    
+    OGR_G_DestroyGeometry(Ogr_geometry);
+    
+    Vect_destroy_line_struct(Points);
+    Vect_destroy_cats_struct(Cats);
+    Vect_destroy_list(cat_list);
+    Vect_destroy_list(line_list);
+    
+    return n_exported;
+}
+
+OGRGeometryH create_polygon(struct Map_info *In, int area,
+                            struct line_pnts *Points)
+{
+    int j, k;
+    OGRGeometryH Ogr_geometry, ring;
+    
+    Vect_get_area_points(In, area, Points);
+    
+    Ogr_geometry = OGR_G_CreateGeometry(wkbPolygon);
+    ring = OGR_G_CreateGeometry(wkbLinearRing);
+    
+    /* Area */
+    for (j = 0; j < Points->n_points; j++) {
+        OGR_G_AddPoint(ring, Points->x[j], Points->y[j],
+                       Points->z[j]);
+    }
+    
+    OGR_G_AddGeometryDirectly(Ogr_geometry, ring);
+    
+    /* Isles */
+    for (k = 0; k < Vect_get_area_num_isles(In, area); k++) {
+        Vect_get_isle_points(In, Vect_get_area_isle(In, area, k),
+                             Points);
+        
+        ring = OGR_G_CreateGeometry(wkbLinearRing);
+        for (j = 0; j < Points->n_points; j++) {
+            OGR_G_AddPoint(ring, Points->x[j], Points->y[j],
+                           Points->z[j]);
+        }
+        OGR_G_AddGeometryDirectly(Ogr_geometry, ring);
+    }
+
+    return Ogr_geometry;
+}

Added: grass/trunk/vector/v.out.ogr/export_lines.c
===================================================================
--- grass/trunk/vector/v.out.ogr/export_lines.c	                        (rev 0)
+++ grass/trunk/vector/v.out.ogr/export_lines.c	2013-12-11 23:22:40 UTC (rev 58447)
@@ -0,0 +1,335 @@
+#include <grass/glocale.h>
+
+#include "local_proto.h"
+
+static int export_lines_single(struct Map_info *, int, int, int, int,
+                               OGRFeatureDefnH, OGRLayerH,
+                               struct field_info *, dbDriver *, int, int *, 
+                               const char **, int, int,
+                               int *, int *);
+static int export_lines_multi(struct Map_info *, int, int, int, int,
+                              OGRFeatureDefnH, OGRLayerH,
+                              struct field_info *, dbDriver *, int, int *, 
+                              const char **, int, int,
+                              int *, int *);
+
+static void line_to_polygon(OGRGeometryH, const struct line_pnts *);
+
+static void add_part(OGRGeometryH, OGRwkbGeometryType,
+                     int, struct line_pnts *);
+
+/* export primitives as single/multi-features */
+int export_lines(struct Map_info *In, int field, int otype, int multi, int donocat, int force_poly,
+                 OGRFeatureDefnH Ogr_featuredefn, OGRLayerH Ogr_layer,
+                 struct field_info *Fi, dbDriver *driver, int ncol, int *colctype, 
+                 const char **colname, int doatt, int nocat,
+                 int *n_noatt, int *n_nocat)
+{
+    if (multi)
+        /* export as multi-features */
+        return export_lines_multi(In, field, otype, donocat, force_poly,
+                                  Ogr_featuredefn, Ogr_layer,
+                                  Fi, driver, ncol, colctype, 
+                                  colname, doatt, nocat,
+                                  n_noatt, n_nocat);
+    
+    /* export as single features */
+    return export_lines_single(In, field, otype, donocat, force_poly,
+                               Ogr_featuredefn, Ogr_layer,
+                               Fi, driver, ncol, colctype, 
+                               colname, doatt, nocat,
+                               n_noatt, n_nocat);
+}
+
+/* export line as single feature */
+int export_lines_single(struct Map_info *In, int field, int otype, int donocat, int force_poly,
+                        OGRFeatureDefnH Ogr_featuredefn, OGRLayerH Ogr_layer,
+                        struct field_info *Fi, dbDriver *driver, int ncol, int *colctype, 
+                        const char **colname, int doatt, int nocat,
+                        int *n_noatt, int *n_nocat)
+{
+    int i, j, n_exported, n_lines;
+    int cat, type;
+
+    struct line_pnts *Points;
+    struct line_cats *Cats;
+
+    OGRGeometryH Ogr_geometry;
+    OGRFeatureH Ogr_feature;
+
+    Points = Vect_new_line_struct();
+    Cats = Vect_new_cats_struct();
+    
+    n_exported = 0;
+    n_lines = Vect_get_num_lines(In);
+    for (i = 1; i <= n_lines; i++) {
+        
+        G_percent(i, n_lines, 5);
+        
+        /* read line */
+        type = Vect_read_line(In, Points, Cats, i);
+        G_debug(2, "line = %d type = %d", i, type);
+        if (!(otype & type)) {
+            /* skip lines with different type */
+            G_debug(2, "type %d not specified -> skipping", type);
+            continue;
+        }
+        
+        /* get line category */
+        Vect_cat_get(Cats, field, &cat);
+        if (cat < 0 && !donocat) {
+            (*n_nocat)++;
+            continue; /* skip lines without category, do not export
+                       * not labeled */
+        }
+        
+        /* build simple features geometry */
+        if ((type == GV_LINE && force_poly) || type == GV_FACE) {
+            /* lines to polygons 
+               faces to 2.5D polygons */
+            Ogr_geometry = OGR_G_CreateGeometry(wkbPolygon);
+            line_to_polygon(Ogr_geometry, Points);
+        }
+        else {
+            Ogr_geometry = OGR_G_CreateGeometry(get_wkbtype(type, otype));
+            if (OGR_G_GetGeometryType(Ogr_geometry) == wkbPoint) {
+                /* GV_POINTS -> wkbPoint */
+                OGR_G_AddPoint(Ogr_geometry, Points->x[0], Points->y[0],
+                               Points->z[0]);
+            }
+            else { /* GV_LINES -> wkbLinestring */
+                for (j = 0; j < Points->n_points; j++) {
+                    OGR_G_AddPoint(Ogr_geometry, Points->x[j], Points->y[j],
+                                   Points->z[j]);
+                }
+            }
+        }
+        
+        /* create feature & set geometry */
+        Ogr_feature = OGR_F_Create(Ogr_featuredefn);
+        OGR_F_SetGeometry(Ogr_feature, Ogr_geometry);
+        
+        /* output one feature for each category, export also features
+         * without category (cat = -1) */
+        for (j = -1; j < Cats->n_cats; j++) {
+            if (j == -1) {
+                if (cat >= 0)
+                    continue;	/* cat(s) exists */
+            }
+            else {
+                if (Cats->field[j] == field)
+                    cat = Cats->cat[j];
+                else
+                    continue;
+            }
+            
+            mk_att(cat, Fi, driver, ncol, colctype, colname, doatt, nocat,
+                   Ogr_feature, n_noatt);
+            OGR_L_CreateFeature(Ogr_layer, Ogr_feature);
+        }
+        OGR_G_DestroyGeometry(Ogr_geometry);
+        OGR_F_Destroy(Ogr_feature);
+
+        n_exported++;
+    }
+
+    Vect_destroy_line_struct(Points);
+    Vect_destroy_cats_struct(Cats);
+    
+    return n_exported;
+}
+
+/* export line as multi-feature */
+int export_lines_multi(struct Map_info *In, int field, int otype, int donocat, int force_poly,
+                       OGRFeatureDefnH Ogr_featuredefn, OGRLayerH Ogr_layer,
+                       struct field_info *Fi, dbDriver *driver, int ncol, int *colctype, 
+                       const char **colname, int doatt, int nocat,
+                       int *n_noatt, int *n_nocat)
+{
+    int i, n_exported;
+    int cat, lcat, ncats_field, line, type, findex, ipart;
+
+    struct line_pnts *Points;
+    struct line_cats *Cats;
+    struct ilist *cat_list, *line_list;
+
+    OGRGeometryH Ogr_geometry;
+    OGRFeatureH Ogr_feature;
+    OGRwkbGeometryType wkbtype, wkbtype_part;
+    
+    Points = Vect_new_line_struct();
+    Cats = Vect_new_cats_struct();
+    cat_list = Vect_new_list();
+    line_list = Vect_new_list();
+
+    n_exported = 0;
+
+    /* check if category index is available for given field */
+    findex = Vect_cidx_get_field_index(In, field);
+    if (findex == -1)
+        G_fatal_error(_("Unable to export multi-features. No category index for layer %d."),
+                      field);
+    
+    /* determine type */
+    type = -1; /* unknown -> GeometryCollection */
+    if (Vect_cidx_get_num_types_by_index(In, findex) == 1)
+        Vect_cidx_get_type_count_by_index(In, findex, 0, &type, NULL);
+    if (force_poly)
+        wkbtype_part = wkbPolygon;
+    else
+        wkbtype_part = get_wkbtype(type, otype);
+    wkbtype = get_multi_wkbtype(wkbtype_part);
+    
+    ncats_field = Vect_cidx_get_unique_cats_by_index(In, findex, cat_list);
+    G_debug(1, "n_cats = %d for layer %d", ncats_field, field);
+
+    for (i = 0; i < cat_list->n_values; i++) {
+        cat = cat_list->value[i];
+        Vect_cidx_find_all(In, field, otype, cat, line_list);
+
+        /* create multi-feature */
+        Ogr_geometry = OGR_G_CreateGeometry(wkbtype);
+
+        /* build simple features geometry, go through all parts */
+        for (ipart = 0; ipart < line_list->n_values; ipart++) {
+            line = line_list->value[ipart];
+            G_debug(3, "cat=%d, line=%d -> part=%d", cat, line, ipart);
+
+            /* read line */
+            type = Vect_read_line(In, Points, Cats, line);
+            
+            /* check for category consistency */
+            Vect_cat_get(Cats, field, &lcat);
+            if (lcat > 0 && lcat != cat)
+                G_fatal_error(_("Unable to create multi-feature. "
+                                "Invalid category %d (should be %d)"),
+                              lcat, cat);
+            
+            /* add part */
+            add_part(Ogr_geometry, wkbtype_part,
+                     type == GV_LINE && force_poly, Points);
+        }
+
+        if (!OGR_G_IsEmpty(Ogr_geometry)) {
+            /* write multi-feature */
+            Ogr_feature = OGR_F_Create(Ogr_featuredefn);
+            OGR_F_SetGeometry(Ogr_feature, Ogr_geometry);
+            
+            mk_att(cat, Fi, driver, ncol, colctype, colname, doatt, nocat,
+                   Ogr_feature, n_noatt);
+            OGR_L_CreateFeature(Ogr_layer, Ogr_feature);
+
+            OGR_F_Destroy(Ogr_feature);
+
+            n_exported++;
+        }
+        else {
+            /* skip empty features */
+            G_debug(3, "multi-feature is empty -> skipped");
+        }
+
+        OGR_G_DestroyGeometry(Ogr_geometry);
+    }
+
+    /* check lines without category, if -c flag is given write them as
+     * one multi-feature */
+    Ogr_geometry = OGR_G_CreateGeometry(wkbtype);
+    
+    Vect_rewind(In);
+    while(TRUE) {
+        type = Vect_read_next_line(In, Points, Cats);
+        if (type < 0)
+            break;
+
+        Vect_cat_get(Cats, field, &cat);
+        if (cat > 0)
+            continue; /* skip features with category */
+        if (cat < 0 && !donocat) {
+            (*n_nocat)++;
+            continue; /* skip lines without category, do not export
+                       * not labeled */
+        }
+
+        /* add part */
+        add_part(Ogr_geometry, wkbtype_part,
+                 type == GV_LINE && force_poly, Points);
+    }
+
+    if (!OGR_G_IsEmpty(Ogr_geometry)) {
+        /* write multi-feature */
+        Ogr_feature = OGR_F_Create(Ogr_featuredefn);
+        OGR_F_SetGeometry(Ogr_feature, Ogr_geometry);
+        
+        mk_att(cat, Fi, driver, ncol, colctype, colname, doatt, nocat,
+               Ogr_feature, n_noatt);
+        OGR_L_CreateFeature(Ogr_layer, Ogr_feature);
+        
+        OGR_F_Destroy(Ogr_feature);
+
+        n_exported++;
+    }
+    else {
+        /* skip empty features */
+        G_debug(3, "multi-feature is empty -> skipped");
+    }
+
+    OGR_G_DestroyGeometry(Ogr_geometry);
+    
+    Vect_destroy_line_struct(Points);
+    Vect_destroy_cats_struct(Cats);
+    Vect_destroy_list(cat_list);
+    Vect_destroy_list(line_list);
+    
+    return n_exported;
+}
+
+/* build polygon for closed line */
+void line_to_polygon(OGRGeometryH Ogr_geometry, const struct line_pnts *Points)
+{
+    int j;
+    OGRGeometryH ring;
+    
+    ring = OGR_G_CreateGeometry(wkbLinearRing);
+    
+    /* create a ring */
+    for (j = 0; j < Points->n_points; j++) {
+        OGR_G_AddPoint(ring, Points->x[j], Points->y[j],
+                       Points->z[j]);
+    }
+
+    /* close ring */
+    if (Points->x[Points->n_points - 1] != Points->x[0] ||
+        Points->y[Points->n_points - 1] != Points->y[0] ||
+        Points->z[Points->n_points - 1] != Points->z[0]) {
+        OGR_G_AddPoint(ring, Points->x[0], Points->y[0],
+                       Points->z[0]);
+    }
+    
+    OGR_G_AddGeometryDirectly(Ogr_geometry, ring);
+}
+
+void add_part(OGRGeometryH Ogr_geometry, OGRwkbGeometryType wkbtype_part,
+              int force_poly, struct line_pnts *Points)
+{
+    int j;
+    OGRGeometryH Ogr_geometry_part;
+
+    Ogr_geometry_part = OGR_G_CreateGeometry(wkbtype_part);
+    if (force_poly) {
+        line_to_polygon(Ogr_geometry_part, Points);
+    }
+    else {
+        if (OGR_G_GetGeometryType(Ogr_geometry_part) == wkbPoint) {
+            /* GV_POINTS -> wkbPoint */
+            OGR_G_AddPoint(Ogr_geometry_part, Points->x[0], Points->y[0],
+                           Points->z[0]);
+        }
+        else { /* GV_LINES -> wkbLinestring */
+            for (j = 0; j < Points->n_points; j++) {
+                OGR_G_AddPoint(Ogr_geometry_part, Points->x[j], Points->y[j],
+                               Points->z[j]);
+            }
+        }
+    }
+    OGR_G_AddGeometryDirectly(Ogr_geometry, Ogr_geometry_part);
+}

Modified: grass/trunk/vector/v.out.ogr/local_proto.h
===================================================================
--- grass/trunk/vector/v.out.ogr/local_proto.h	2013-12-11 20:21:50 UTC (rev 58446)
+++ grass/trunk/vector/v.out.ogr/local_proto.h	2013-12-11 23:22:40 UTC (rev 58447)
@@ -12,11 +12,11 @@
 
 struct Options {
     struct Option *input, *dsn, *layer, *type, *format,
-	*field, *dsco, *lco;
+	*field, *dsco, *lco, *otype;
 };
 
 struct Flags {
-    struct Flag *cat, *esristyle, *poly, *update, *nocat, *new, *append, *force2d;
+    struct Flag *cat, *esristyle, *poly, *update, *nocat, *new, *append, *force2d, *multi;
 };
 
 /* args.c */
@@ -24,9 +24,9 @@
 		struct Options*, struct Flags *);
 
 /* attributes.c */
-int mk_att(int cat, struct field_info *Fi, dbDriver *Driver,
-	   int ncol, int *colctype, const char **colname, int doatt, int nocat,
-	   OGRFeatureH Ogr_feature, int *, int *);
+int mk_att(int, struct field_info *, dbDriver *,
+	   int, int *, const char **, int, int,
+	   OGRFeatureH, int *);
 
 /* list.c */
 char *OGR_list_write_drivers();
@@ -34,3 +34,26 @@
 /* create.c */
 void create_ogr_layer(const char *, const char *, const char *,
 		      unsigned int, char **, char **);
+OGRwkbGeometryType get_multi_wkbtype(OGRwkbGeometryType);
+OGRwkbGeometryType get_wkbtype(int, int);
+
+/* export_lines.c */
+int export_lines(struct Map_info *, int, int, int, int, int,
+                 OGRFeatureDefnH, OGRLayerH,
+                 struct field_info *, dbDriver *, int, int *, 
+                 const char **, int, int,
+                 int *, int *);
+
+/* export_lines_3d.c */
+int export_lines_3d(struct Map_info *, int, int, int, 
+                    OGRFeatureDefnH, OGRLayerH,
+                    struct field_info *, dbDriver *, int, int *, 
+                    const char **, int, int,
+                    int *, int *);
+
+/* export_areas.c */
+int export_areas(struct Map_info *, int, int, int, 
+                 OGRFeatureDefnH, OGRLayerH,
+                 struct field_info *, dbDriver *, int, int *, 
+                 const char **, int, int,
+                 int *, int *);

Modified: grass/trunk/vector/v.out.ogr/main.c
===================================================================
--- grass/trunk/vector/v.out.ogr/main.c	2013-12-11 20:21:50 UTC (rev 58446)
+++ grass/trunk/vector/v.out.ogr/main.c	2013-12-11 23:22:40 UTC (rev 58447)
@@ -5,11 +5,11 @@
  *
  * AUTHOR(S):    Radim Blazek
  *               Some extensions: Markus Neteler, Benjamin Ducke
- *               Update for GRASS 7 by Martin Landa <landa.martin gmail.com> (create new OGR layer)
+ *               Multi-features support by Martin Landa <landa.martin gmail.com> 
  *
  * PURPOSE:      Converts GRASS vector to one of supported OGR vector formats.
  *
- * COPYRIGHT:    (C) 2001-2009, 2011 by the GRASS Development Team
+ * COPYRIGHT:    (C) 2001-2013 by the GRASS Development Team
  *
  *               This program is free software under the GNU General
  *               Public License (>=v2).  Read the file COPYING that
@@ -29,10 +29,11 @@
 
 int main(int argc, char *argv[])
 {
-    int i, j, k, centroid, otype, donocat;
+    int i, otype, ftype, donocat;
     int num_to_export;
     int field;
     int overwrite, found;
+
     struct GModule *module;
     struct Options options;
     struct Flags flags;
@@ -45,9 +46,6 @@
 
     /* Vector */
     struct Map_info In;
-    struct line_pnts *Points;
-    struct line_cats *Cats;
-    int type, cat;
 
     /* Attributes */
     int doatt = 0, ncol = 0, colsqltype, colwidth, keycol = -1;
@@ -59,8 +57,8 @@
     dbString dbstring;
     dbColumn *Column;
 
-    int fout, fskip;		/* features written/ skip */
-    int nocat, noatt, nocatskip;	/* number of features without cats/atts written/skip */
+    int n_feat;                        /* number of written features */
+    int n_nocat, n_noatt, n_nocatskip; /* number of features without cats/atts written/skip */
 
     /* OGR */
     int drn;
@@ -69,10 +67,8 @@
     OGRSFDriverH Ogr_driver;
     OGRLayerH Ogr_layer;
     OGRFieldDefnH Ogr_field;
-    OGRFeatureH Ogr_feature;
     OGRFeatureDefnH Ogr_featuredefn;
-    OGRGeometryH Ogr_geometry;
-    OGRwkbGeometryType wkbtype = wkbUnknown;	/* ?? */
+    OGRwkbGeometryType wkbtype = wkbUnknown;
     OGRSpatialReferenceH Ogr_projection;
     char **papszDSCO = NULL, **papszLCO = NULL;
     int num_types;
@@ -85,8 +81,9 @@
     G_add_keyword(_("export"));
     G_add_keyword("OGR");
 
-    module->description =
-	_("Converts a vector map to any of the supported OGR vector formats.");
+    module->label =
+	_("Exports a vector map layer to any of the supported OGR vector formats.");
+    module->description = _("By default a vector map layer is exported to Esri Shapefile format.");
     module->overwrite = TRUE;
     
     /* parse & read options */
@@ -187,6 +184,7 @@
 
     /* check output feature type */
     otype = Vect_option_to_types(options.type);
+    ftype = Vect_option_to_types(options.otype);
 
     if (!options.layer->answer) {
 	char xname[GNAME_MAX], xmapset[GMAPSET_MAX];
@@ -197,20 +195,37 @@
 	    options.layer->answer = G_store(options.input->answer);
     }
 
-    if (otype & GV_POINTS)
-	wkbtype = wkbPoint;
-    else if (otype & GV_LINES)
-	wkbtype = wkbLineString;
-    else if (otype & GV_AREA)
-	wkbtype = wkbPolygon;
-    else if (otype & GV_FACE)
-	wkbtype = wkbPolygon25D;
-    else if (otype & GV_VOLUME)
-	wkbtype = wkbPolygon25D;
+    if (flags.poly->answer) {
+        if (!flags.multi->answer)
+            wkbtype = wkbPolygon;
+        else
+            wkbtype = wkbMultiPolygon;
+    }
+    else if (otype & GV_POINTS) {
+        if (!flags.multi->answer)
+            wkbtype = wkbPoint;
+        else
+            wkbtype = wkbMultiPoint;
+    }
+    else if (otype & GV_LINES || ftype == GV_LINE) {
+        if (!flags.multi->answer)
+            wkbtype = wkbLineString;
+        else
+            wkbtype = wkbMultiLineString;
+    }
+    else if (otype & GV_AREA) {
+        if (!flags.multi->answer)
+            wkbtype = wkbPolygon;
+        else
+            wkbtype = wkbMultiPolygon;
+    }
+    else if (otype & (GV_FACE | GV_VOLUME)) {
+        if (!flags.multi->answer)
+            wkbtype = wkbPolygon25D;
+        else
+            wkbtype = wkbMultiPolygon25D;
+    }
 
-    if (flags.poly->answer)
-	wkbtype = wkbPolygon;
-
     if (((GV_POINTS & otype) && (GV_LINES & otype)) ||
 	((GV_POINTS & otype) && (GV_AREA & otype)) ||
 	((GV_POINTS & otype) && (GV_FACE & otype)) ||
@@ -225,7 +240,6 @@
 	((GV_KERNEL & otype) && (GV_AREA & otype)) ||
 	((GV_KERNEL & otype) && (GV_FACE & otype)) ||
 	((GV_KERNEL & otype) && (GV_VOLUME & otype))
-
 	) {
 	G_warning(_("The combination of types is not supported"
 		    " by all formats."));
@@ -266,9 +280,6 @@
     else
 	donocat = 0;
 
-    Points = Vect_new_line_struct();
-    Cats = Vect_new_cats_struct();
-
     if ((GV_AREA & otype) && Vect_get_num_islands(&In) > 0 &&
 	flags.cat->answer)
 	G_warning(_("The map contains islands. With the -c flag, "
@@ -515,7 +526,7 @@
 	else {
 	    G_warning(_("Vector map <%s> is 3D. "
 			"Use format specific layer creation options (parameter 'lco') "
-			"to export in 3D rather than 2D (default)."),
+			"to export <in 3D rather than 2D (default)."),
 		      options.input->answer);
 	}
     }
@@ -647,291 +658,43 @@
     
     Ogr_featuredefn = OGR_L_GetLayerDefn(Ogr_layer);
 
-    fout = fskip = nocat = noatt = nocatskip = 0;
+    n_feat = n_nocat = n_noatt = n_nocatskip = 0;
 
     if (OGR_L_TestCapability(Ogr_layer, OLCTransactions))
 	OGR_L_StartTransaction(Ogr_layer);
     
     /* Lines (run always to count features of different type) */
-    if ((otype & GV_POINTS) || (otype & GV_LINES)) {
+    if (otype & (GV_POINTS | GV_LINES | GV_KERNEL | GV_FACE)) {
         G_message(_("Exporting %d features..."), Vect_get_num_primitives(&In, otype));
-	for (i = 1; i <= Vect_get_num_lines(&In); i++) {
 
-	    G_percent(i, Vect_get_num_lines(&In), 1);
-
-	    type = Vect_read_line(&In, Points, Cats, i);
-	    G_debug(2, "line = %d type = %d", i, type);
-	    if (!(otype & type)) {
-		G_debug(2, "type %d not specified -> skipping", type);
-		fskip++;
-		continue;
-	    }
-
-	    Vect_cat_get(Cats, field, &cat);
-	    if (cat < 0 && !donocat) {	/* Do not export not labeled */
-		nocatskip++;
-		continue;
-	    }
-
-	    /* Geometry */
-	    if (type == GV_LINE && flags.poly->answer) {
-		OGRGeometryH ring;
-
-		ring = OGR_G_CreateGeometry(wkbLinearRing);
-		Ogr_geometry = OGR_G_CreateGeometry(wkbPolygon);
-
-		/* Area */
-		for (j = 0; j < Points->n_points; j++) {
-		    OGR_G_AddPoint(ring, Points->x[j], Points->y[j],
-				   Points->z[j]);
-		}
-		if (Points->x[Points->n_points - 1] != Points->x[0] ||
-		    Points->y[Points->n_points - 1] != Points->y[0] ||
-		    Points->z[Points->n_points - 1] != Points->z[0]) {
-		    OGR_G_AddPoint(ring, Points->x[0], Points->y[0],
-				   Points->z[0]);
-		}
-
-		OGR_G_AddGeometryDirectly(Ogr_geometry, ring);
-	    }
-	    else if ((type == GV_POINT) ||
-		     ((type == GV_CENTROID) && (otype & GV_CENTROID))) {
-		Ogr_geometry = OGR_G_CreateGeometry(wkbPoint);
-		OGR_G_AddPoint(Ogr_geometry, Points->x[0], Points->y[0],
-			       Points->z[0]);
-	    }
-	    else {		/* GV_LINE or GV_BOUNDARY */
-		Ogr_geometry = OGR_G_CreateGeometry(wkbLineString);
-		for (j = 0; j < Points->n_points; j++) {
-		    OGR_G_AddPoint(Ogr_geometry, Points->x[j], Points->y[j],
-				   Points->z[j]);
-		}
-	    }
-	    Ogr_feature = OGR_F_Create(Ogr_featuredefn);
-
-	    OGR_F_SetGeometry(Ogr_feature, Ogr_geometry);
-
-	    /* Output one feature for each category */
-	    for (j = -1; j < Cats->n_cats; j++) {
-		if (j == -1) {
-		    if (cat >= 0)
-			continue;	/* cat(s) exists */
-		}
-		else {
-		    if (Cats->field[j] == field)
-			cat = Cats->cat[j];
-		    else
-			continue;
-		}
-
-		mk_att(cat, Fi, Driver, ncol, colctype, colname, doatt, flags.nocat->answer,
-		       Ogr_feature, &noatt, &fout);
-		OGR_L_CreateFeature(Ogr_layer, Ogr_feature);
-	    }
-	    OGR_G_DestroyGeometry(Ogr_geometry);
-	    OGR_F_Destroy(Ogr_feature);
-	}
+        n_feat += export_lines(&In, field, otype, flags.multi->answer ? TRUE : FALSE,
+                               donocat, flags.poly->answer ? TRUE : FALSE,
+                               Ogr_featuredefn, Ogr_layer,
+                               Fi, Driver, ncol, colctype, 
+                               colname, doatt, flags.nocat->answer ? TRUE : FALSE,
+                               &n_noatt, &n_nocatskip);
     }
 
     /* Areas (run always to count features of different type) */
-    if (Vect_get_num_areas(&In) > 0 && otype & GV_AREA) {
-	G_message(_("Exporting %i areas (may take some time)..."),
+    if (Vect_get_num_areas(&In) > 0 && (otype & GV_AREA)) {
+	G_message(_("Exporting %d areas (may take some time)..."),
 		  Vect_get_num_areas(&In));
-	for (i = 1; i <= Vect_get_num_areas(&In); i++) {
-	    OGRGeometryH ring;
 
-	    G_percent(i, Vect_get_num_areas(&In), 1);
-
-	    centroid = Vect_get_area_centroid(&In, i);
-	    cat = -1;
-	    if (centroid > 0) {
-		Vect_read_line(&In, NULL, Cats, centroid);
-		Vect_cat_get(Cats, field, &cat);
-	    }
-	    G_debug(3, "area = %d centroid = %d ncats = %d", i, centroid,
-		    Cats->n_cats);
-	    if (cat < 0 && !donocat) {	/* Do not export not labeled */
-		nocatskip++;
-		continue;
-	    }
-
-	    Vect_get_area_points(&In, i, Points);
-
-	    /* Geometry */
-	    Ogr_geometry = OGR_G_CreateGeometry(wkbPolygon);
-
-	    ring = OGR_G_CreateGeometry(wkbLinearRing);
-
-	    /* Area */
-	    for (j = 0; j < Points->n_points; j++) {
-		OGR_G_AddPoint(ring, Points->x[j], Points->y[j],
-			       Points->z[j]);
-	    }
-
-	    OGR_G_AddGeometryDirectly(Ogr_geometry, ring);
-
-	    /* Isles */
-	    for (k = 0; k < Vect_get_area_num_isles(&In, i); k++) {
-		Vect_get_isle_points(&In, Vect_get_area_isle(&In, i, k),
-				     Points);
-
-		ring = OGR_G_CreateGeometry(wkbLinearRing);
-		for (j = 0; j < Points->n_points; j++) {
-		    OGR_G_AddPoint(ring, Points->x[j], Points->y[j],
-				   Points->z[j]);
-		}
-		OGR_G_AddGeometryDirectly(Ogr_geometry, ring);
-	    }
-
-	    Ogr_feature = OGR_F_Create(Ogr_featuredefn);
-	    OGR_F_SetGeometry(Ogr_feature, Ogr_geometry);
-
-	    /* Output one feature for each category */
-	    for (j = -1; j < Cats->n_cats; j++) {
-		if (j == -1) {
-		    if (cat >= 0)
-			continue;	/* cat(s) exists */
-		}
-		else {
-		    if (Cats->field[j] == field)
-			cat = Cats->cat[j];
-		    else
-			continue;
-		}
-
-		mk_att(cat, Fi, Driver, ncol, colctype, colname, doatt, flags.nocat->answer,
-		       Ogr_feature, &noatt, &fout);
-		OGR_L_CreateFeature(Ogr_layer, Ogr_feature);
-	    }
-	    OGR_G_DestroyGeometry(Ogr_geometry);
-	    OGR_F_Destroy(Ogr_feature);
-	}
+        n_feat += export_areas(&In, field, flags.multi->answer ? TRUE : FALSE, donocat, 
+                               Ogr_featuredefn, Ogr_layer,
+                               Fi, Driver, ncol, colctype, 
+                               colname, doatt, flags.nocat->answer ? TRUE : FALSE,
+                               &n_noatt, &n_nocatskip);
     }
 
-    /* Faces (run always to count features of different type)  - Faces are similar to lines */
-    if (Vect_get_num_primitives(&In, GV_FACE) > 0 && otype & GV_FACE) {
-	G_message(_("Exporting %i faces..."), Vect_get_num_faces(&In));
-	for (i = 1; i <= Vect_get_num_faces(&In); i++) {
-	    OGRGeometryH ring;
-
-	    G_percent(i, Vect_get_num_faces(&In), 1);
-
-	    type = Vect_read_line(&In, Points, Cats, i);
-	    G_debug(3, "line type = %d", type);
-
-	    cat = -1;
-	    Vect_cat_get(Cats, field, &cat);
-
-	    G_debug(3, "face = %d ncats = %d", i, Cats->n_cats);
-	    if (cat < 0 && !donocat) {	/* Do not export not labeled */
-		nocatskip++;
-		continue;
-	    }
-
-	    if (type & GV_FACE) {
-
-		Ogr_feature = OGR_F_Create(Ogr_featuredefn);
-
-		/* Geometry */
-		Ogr_geometry = OGR_G_CreateGeometry(wkbPolygon25D);
-		ring = OGR_G_CreateGeometry(wkbLinearRing);
-
-		/* Face */
-		for (j = 0; j < Points->n_points; j++) {
-		    OGR_G_AddPoint(ring, Points->x[j], Points->y[j],
-				   Points->z[j]);
-		}
-
-		OGR_G_AddGeometryDirectly(Ogr_geometry, ring);
-
-		OGR_F_SetGeometry(Ogr_feature, Ogr_geometry);
-
-		/* Output one feature for each category */
-		for (j = -1; j < Cats->n_cats; j++) {
-		    if (j == -1) {
-			if (cat >= 0)
-			    continue;	/* cat(s) exists */
-		    }
-		    else {
-			if (Cats->field[j] == field)
-			    cat = Cats->cat[j];
-			else
-			    continue;
-		    }
-
-		    mk_att(cat, Fi, Driver, ncol, colctype, colname, doatt, flags.nocat->answer,
-			   Ogr_feature, &noatt, &fout);
-		    OGR_L_CreateFeature(Ogr_layer, Ogr_feature);
-		}
-
-		OGR_G_DestroyGeometry(Ogr_geometry);
-		OGR_F_Destroy(Ogr_feature);
-	    }			/* if type & GV_FACE */
-	}			/* for */
-    }
-
-    /* Kernels */
-    if (Vect_get_num_primitives(&In, GV_KERNEL) > 0 && otype & GV_KERNEL) {
-	G_message(_("Exporting %i kernels..."), Vect_get_num_kernels(&In));
-	for (i = 1; i <= Vect_get_num_lines(&In); i++) {
-
-	    G_percent(i, Vect_get_num_lines(&In), 1);
-
-	    type = Vect_read_line(&In, Points, Cats, i);
-	    G_debug(2, "line = %d type = %d", i, type);
-	    if (!(otype & type)) {
-		G_debug(2, "type %d not specified -> skipping", type);
-		fskip++;
-		continue;
-	    }
-
-	    Vect_cat_get(Cats, field, &cat);
-	    if (cat < 0 && !donocat) {	/* Do not export not labeled */
-		nocatskip++;
-		continue;
-	    }
-
-	    /* Geometry */
-	    if (type == GV_KERNEL) {
-		Ogr_geometry = OGR_G_CreateGeometry(wkbPoint);
-		OGR_G_AddPoint(Ogr_geometry, Points->x[0], Points->y[0],
-			       Points->z[0]);
-
-		Ogr_feature = OGR_F_Create(Ogr_featuredefn);
-
-		OGR_F_SetGeometry(Ogr_feature, Ogr_geometry);
-
-		/* Output one feature for each category */
-		for (j = -1; j < Cats->n_cats; j++) {
-		    if (j == -1) {
-			if (cat >= 0)
-			    continue;	/* cat(s) exists */
-		    }
-		    else {
-			if (Cats->field[j] == field)
-			    cat = Cats->cat[j];
-			else
-			    continue;
-		    }
-
-		    mk_att(cat, Fi, Driver, ncol, colctype, colname, doatt, flags.nocat->answer,
-			   Ogr_feature, &noatt, &fout);
-		    OGR_L_CreateFeature(Ogr_layer, Ogr_feature);
-		}
-		OGR_G_DestroyGeometry(Ogr_geometry);
-		OGR_F_Destroy(Ogr_feature);
-	    }
-	}
-    }
-
     /*
-       TODO:   Volumes. Do not export kernels here, that's already done.
-       We do need to worry about holes, though.
-       NOTE: We can probably just merge this with faces export function.
-       Except for GRASS, which output format would know the difference?
+       TODO: Volumes. Do not export kernels here, that's already done.
+       We do need to worry about holes, though. NOTE: We can probably
+       just merge this with faces export function. Except for GRASS,
+       which output format would know the difference?
      */
-    if ((otype & GV_VOLUME)) {
-	G_message(_("Exporting %i volumes..."), Vect_get_num_volumes(&In));
+    if (Vect_get_num_volumes(&In) > 0 && (otype & GV_VOLUME)) {
+	G_message(_("Exporting %d volumes..."), Vect_get_num_volumes(&In));
 	G_warning(_("Export of volumes not implemented yet. Skipping."));
     }
 
@@ -948,26 +711,27 @@
     }
 
     /* Summary */
-    if (nocat > 0)
-	G_warning(_("%d features without category were written"), nocat);
-    if (noatt > 0)
-	G_warning(_("%d features without attributes were written"), noatt);
-    if (nocatskip > 0)
+    if (n_nocat > 0)
+	G_important_message(_("%d features without category were written"), n_nocat);
+    if (n_noatt > 0)
+	G_important_message(_("%d features without attributes were written"), n_noatt);
+
+    if (n_nocatskip > 0)
 	G_warning(_("%d features without category were skipped. "
                     "Features without category are written only when -%c flag is given."),
-		  nocatskip, flags.cat->key);
+		  n_nocatskip, flags.cat->key);
 
-    /* Enable this? May be confusing that for area type are not reported
-     *    all boundaries/centroids.
-     *  OTOH why should be reported? */
+    /* Enable this? May be confusing that for area type are not
+     * reported all boundaries/centroids. OTOH why should be
+     * reported? */
     /*
        if (((otype & GV_POINTS) || (otype & GV_LINES)) && fskip > 0)
        G_warning ("%d features of different type skip", fskip);
      */
 
-    if (fout < 1)
+    if (n_feat < 1)
         G_warning(_("Output layer is empty, no features written"));
-    G_done_msg(_("%d features (%s type) written to <%s> (%s format)."), fout,
+    G_done_msg(_("%d features (%s type) written to <%s> (%s format)."), n_feat,
                OGRGeometryTypeToName(wkbtype),
 	       options.layer->answer, options.format->answer);
 

Modified: grass/trunk/vector/v.out.ogr/v.out.ogr.html
===================================================================
--- grass/trunk/vector/v.out.ogr/v.out.ogr.html	2013-12-11 20:21:50 UTC (rev 58446)
+++ grass/trunk/vector/v.out.ogr/v.out.ogr.html	2013-12-11 23:22:40 UTC (rev 58447)
@@ -1,67 +1,109 @@
 <h2>DESCRIPTION</h2>
 
-<em>v.out.ogr</em> converts GRASS vector data to
-<a href="http://www.gdal.org/ogr/">OGR</a> format. 
-OGR (Simple Features Library) is part of the 
+<em>v.out.ogr</em> converts GRASS vector map layer to any of the
+supported <a href="http://www.gdal.org/ogr/">OGR</a> vector formats
+(like a Esri Shapefile, SpatiaLite or GML).
+
+<p>
+OGR (Simple Features Library) is part of the
 <a href="http://www.gdal.org">GDAL</a> library, so you need to
-install gdal to use <em>v.out.ogr</em>. 
+install this library to use <em>v.out.ogr</em>. 
 
-<h3>Supported OGR Vector Formats</h3>
+<p>
+The OGR library supports many various formats including:
 
-<a href="http://www.gdal.org/ogr/drv_shapefile.html">ESRI Shapefile</a><br>
-<a href="http://www.gdal.org/ogr/drv_csv.html">CSV</a><br>
-<a href="http://www.gdal.org/ogr/drv_gml.html">GML</a><br>
-<a href="http://www.gdal.org/ogr/drv_kml.html">KML</a><br>
-<a href="http://www.gdal.org/ogr/drv_mitab.html">Mapinfo File</a><br>
-<a href="http://www.gdal.org/ogr/drv_pg.html">PostgreSQL/PostGIS</a><br>
-<a href="http://www.gdal.org/ogr/drv_tiger.html">TIGER</a>
+<ul>
+  <li><a href="http://www.gdal.org/ogr/drv_shapefile.html">ESRI Shapefile</a></li>
+  <li><a href="http://www.gdal.org/ogr/drv_pg.html">PostGIS</a></li>
+  <li><a href="http://www.gdal.org/ogr/drv_sqlite.html">SpatiaLite</a></li>
+  <li><a href="http://www.gdal.org/ogr/drv_csv.html">CSV</a></li>
+  <li><a href="http://www.gdal.org/ogr/drv_gml.html">GML</a></li>
+  <li><a href="http://www.gdal.org/ogr/drv_kml.html">KML</a></li>
+  <li><a href="http://www.gdal.org/ogr/drv_mitab.html">Mapinfo File</a></li>
+  <li><a href="http://www.gdal.org/ogr/drv_tiger.html">TIGER</a></li>
+  <li>... and many others</li>
+</ul>
 
 <p>
-For further available drivers go 
+For further available other supported formats go 
 <a href="http://www.gdal.org/ogr/ogr_formats.html">here</a>.
 
 <h2>NOTES</h2>
 
-By default, islands will appear as holes inside surrounding areas.
-To export areas with holes into, e.g., a Shapefile, and make the 
-holes appear as filled areas, the flag <em>-c</em> has to be used.
-<p>The "-z" flag can be used to automatically export a 3D map to a 3D Shapefile, instead 
-of setting the correct <em>lco=</em> option manually.
+By default, islands will appear as holes inside surrounding areas. To
+export polygons with holes into, e.g., a Esri Shapefile, and make the
+holes appear as filled areas, the flag <b>-c</b> has to be used.
 
+<p>
+<em>v.out.ogr</em> exports 3D vector data as 2.5D simple features if
+possible (not supported by all formats). For exporting 3D vector data
+as 2D simple features, use <b>-2</b> flag.
+
+<p>
+By default, <em>v.out.ogr</em> converts GRASS vector data to single
+simple features. If GRASS features has more categories defined in
+given <b>layer</b>, then the features is exported several times. GRASS
+features without category are skipped by default. To export features
+also without category, the <b>-c</b> flag must be given.
+
+<p>
+When <b>-m</b> flag is given, <em>v.out.ogr</em> export GRASS vector
+data as multi-features based on their category(ies). Multi-feature is
+formed by GRASS features with the same category. When <b>-c</b> flag
+is given, the module also export GRASS features without category as
+one multi-feature. Note that multi-features are not supported by all
+formats.
+
 <h2>EXAMPLES</h2>
 
-<h3>Export to Shapefile</h3>
+<h3>Export to Esri Shapefile</h3>
 
 Export lines from GRASS vector map to Shapefile format:
+
 <div class="code"><pre>
 v.out.ogr input=lines type=line dsn=lines.shp
 </pre></div>
-<p>Export areas from GRASS vector map to Shapefile format, converting
-islands (holes) to filled areas (generates /tmp/testogr.shp and related files):
+
+<p>
+Export areas from GRASS vector map to Shapefile format, converting
+islands (holes) to filled polygons:
+
 <div class="code"><pre>
 v.out.ogr -c input=areas_islands type=area dsn=areas_islands.shp
 </pre></div>
-<p>Export 3D lines from GRASS vector map to Shapefile format:
+
+<p>
+Export 3D lines from GRASS vector map to Shapefile format:
+
 <div class="code"><pre>
 v.out.ogr input=lines_3d type=line dsn=lines_3d.shp lco="SHPT=ARCZ"
 </pre></div>
-<p>Export 3D points (e.g., Lidar points) from GRASS vector map to Shapefile format
+
+<p>
+Export 3D points (e.g., Lidar points) from GRASS vector map to Shapefile format
+
 <div class="code"><pre>
 v.out.ogr points_3d type=point dsn=points_3d.shp lco="SHPT=POINTZ"
 </pre></div>
-<p>Export 3D faces from GRASS vector map to Shapefile format:
+
+<p>
+Export 3D faces from GRASS vector map to Shapefile format:
 <div class="code"><pre>
 v.out.ogr input=objects_3d type=face dsn=faces_3d.shp lco="SHPT=POLYGONZ"
 </pre></div>
-<p>Export 3D faces from GRASS vector map to Shapefile format, automatic 3D setting:
+
+<p>
+Export 3D faces from GRASS vector map to Shapefile format, automatic 3D setting:
+
 <div class="code"><pre>
-v.out.ogr input=objects_3d type=face dsn=faces_3d.shp -z"
+v.out.ogr input=objects_3d type=face dsn=faces_3d.shp"
 </pre></div>
 
 <h3>Export to GML</h3>
 
 Export lines from GRASS vector map to GML format
- (generates /tmp/testogr.gml file with layer 'testogr'):
+ (generates '/tmp/testogr.gml' file with layer 'testogr'):
+
 <div class="code"><pre>
 v.out.ogr input=multi type=line dsn=/tmp/testogr.gml olayer=testogr format=GML 
 </pre></div>
@@ -69,24 +111,29 @@
 <h3>Export to PostgreSQL/PostGIS</h3>
 
 Export areas from GRASS vector map directly to PostGIS:
+
 <div class="code"><pre>
-v.out.ogr input=polygons type=area \
-          dsn="PG:host=localhost dbname=postgis user=postgres" \
-          olayer=polymap format=PostgreSQL
+v.out.ogr input=polygons type=area dsn="PG:host=localhost dbname=postgis user=postgres" olayer=polymap format=PostgreSQL
 </pre></div>
 
+<i>Note:</i> For exporting GRASS vector data to PostGIS database
+should be used <em><a href="v.out.postgis.html">v.out.postgis</a></em>
+module. This module supports beside simple features also topological
+format PostGIS Topology.
+
 <h3>Export to KML (Google Earth)</h3>
 
-<b>Example 1 (Latitude-Longitude location):</b><br>
+<p>
 Export faces (3D vectors) from GRASS vector map to KML format for Google Earth:
+
 <div class="code"><pre>
-v.out.ogr input=buildings_3d dsn=buildings_3d.kml olayer=buildings_3d \
-          format=KML type=face
+v.out.ogr input=buildings_3d dsn=buildings_3d.kml olayer=buildings_3d format=KML type=face
 </pre></div>
 
-<p><b>Example 2 (Latitude-Longitude location):</b><br>
+<p>
 Generate and export GRASS vector "asteroid" map (faces, 3D vectors) to
- KML format for Google Earth:
+KML format for Google Earth:
+
 <div class="code"><pre>
 # near Raleigh (NC, USA)
 g.region n=35.73952587 s=35.73279182 w=-78.68263928 e=-78.67499517
@@ -102,32 +149,35 @@
 v.hull input=random3d output="random3d_hull"
 
 # export to KML 3D
-v.out.ogr input=random3d_hull dsn=random3d_hull.kml format=KML \
-          type=face dsco="AltitudeMode=absolute"
+v.out.ogr input=random3d_hull dsn=random3d_hull.kml format=KML type=face dsco="AltitudeMode=absolute"
 
 # now open KML file 'random3d_hull.kml' in Google Earth or NASA WorldWind or ...
 </pre></div>
 
-
 <h2>REFERENCES</h2>
 
-<a href="http://www.gdal.org/ogr/">OGR vector library</a>
-<br>
-<a href="http://www.gdal.org/ogr/ogr__api_8h.html">OGR vector library C API</a>
-documentation
+<ul>
+<li><a href="http://www.gdal.org/ogr/">OGR vector library</a></li>
+<li><a href="http://www.gdal.org/ogr/ogr__api_8h.html">OGR vector library C API</a>
+  documentation</li>
+</ul>
 
-
 <h2>SEE ALSO</h2>
 
 <em>
+<a href="v.out.postgis.html">v.out.postgis</a>,
 <a href="db.out.ogr.html">db.out.ogr</a>,
 <a href="v.external.html">v.external</a>,
+<a href="v.external.out.html">v.external.out</a>,
 <a href="v.in.ogr.html">v.in.ogr</a>
 </em>
 
 <h2>AUTHORS</h2>
 
 Radim Blazek, ITC-Irst, Trento, Italy<br>
-Some contributions: Markus Neteler, Martin Landa
-<p><i>Last changed: $Date$</i>
+Some contributions: Markus Neteler<br>
+Multi-feature support by Martin Landa, Czech Technical University in Prague, 2013
 
+<p>
+<i>Last changed: $Date$</i>
+



More information about the grass-commit mailing list