[GRASS-SVN] r72671 - grass/trunk/vector/v.extract

svn_grass at osgeo.org svn_grass at osgeo.org
Fri May 4 10:14:59 PDT 2018


Author: mmetz
Date: 2018-05-04 10:14:59 -0700 (Fri, 04 May 2018)
New Revision: 72671

Modified:
   grass/trunk/vector/v.extract/extract.c
   grass/trunk/vector/v.extract/local_proto.h
   grass/trunk/vector/v.extract/main.c
Log:
v.extract: add option to dissolve by attribute, preserving categories and attribute values

Modified: grass/trunk/vector/v.extract/extract.c
===================================================================
--- grass/trunk/vector/v.extract/extract.c	2018-05-04 14:47:55 UTC (rev 72670)
+++ grass/trunk/vector/v.extract/extract.c	2018-05-04 17:14:59 UTC (rev 72671)
@@ -107,12 +107,15 @@
 
 /* check if output cats of left and right area match */
 static int areas_new_cats_match(struct Map_info *In, int area1, int area2,
-				int type_only, int field, int new, int reverse)
+				int type_only, int field, int new, int reverse,
+				char *dissolve_key, int coltype, 
+				dbDriver *driver, struct field_info *Fi)
 {
     int i, j, found;
     int centroid1, centroid2;
     static struct line_cats *Cats1 = NULL;
     static struct line_cats *Cats2 = NULL;
+    dbValue val1, val2;
 
     G_debug(4, "areas_new_cats_match area1 = %d area2 = %d", area1, area2);
 
@@ -141,6 +144,10 @@
 
     for (i = 0; i < Cats1->n_cats; i++) {
 	found = 0;
+	if (dissolve_key && Cats1->field[i] == field) {
+	    db_select_value(driver, Fi->table, Fi->key, Cats1->cat[i], dissolve_key,
+			    &val1);
+	}
 	for (j = 0; j < Cats2->n_cats; j++) {
 	    G_debug(5, "%d:%d x %d:%d", Cats1->field[i], Cats1->cat[i],
 		    Cats2->field[j], Cats2->cat[j]);
@@ -149,6 +156,31 @@
 		found = 1;
 		break;
 	    }
+	    if (dissolve_key) {
+		db_select_value(driver, Fi->table, Fi->key, Cats2->cat[j], dissolve_key,
+				&val2);
+		/* compare db values */
+		switch (coltype)
+		{
+		case DB_C_TYPE_INT: {
+		    if (db_get_value_int(&val1) == db_get_value_int(&val2))
+			found = 1;
+		    break;
+		}
+		case DB_C_TYPE_DOUBLE: {
+		    if (db_get_value_int(&val1) == db_get_value_double(&val2))
+			found = 1;
+		    break;
+		}
+		default: {	/* STRING and DATETIME */
+		    if (G_strcasecmp(db_get_value_string(&val1), db_get_value_string(&val2)) == 0)
+			found = 1;
+		    break;
+		}
+		}
+		if (found == 1)
+		    break;
+	    }
 	}
 	if (!found)
 	    return 0;
@@ -192,7 +224,7 @@
 
 int extract_line(int num_index, int *num_array, struct Map_info *In,
 		 struct Map_info *Out, int new, int select_type, int dissolve,
-		 int field, int type_only, int reverse)
+		 char *dissolve_key, int field, int type_only, int reverse)
 {
     G_debug(2, "extract_line(num_index=%d, new=%d, select_type=%d,"
                " dissolve=%d, field=%d, type_only=%d, reverse=%d)",
@@ -210,6 +242,9 @@
     int centroid_in_area;	/* centroid is in area */
     int type;
     int i, tmp, write, area;
+    struct field_info *Fi;
+    dbDriver *driver;
+    int coltype;
 
     /* Initialize the Point structure, ONCE */
     Points = Vect_new_line_struct();
@@ -219,6 +254,29 @@
     cats_array = num_array;
     ncats_array = num_index;
 
+    /* dissolve by key column */
+    Fi = NULL;
+    driver = NULL;
+    coltype = -1;
+    if (dissolve_key) {
+	Fi = Vect_get_field(In, field);
+	if (!Fi) {
+	    G_fatal_error(_("Database connection not defined for layer <%d>"),
+			  field);
+	}
+
+	G_verbose_message(_("Loading categories from table <%s>..."), Fi->table);
+
+	driver = db_start_driver_open_database(Fi->driver, Fi->database);
+	if (driver == NULL)
+	    G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
+			  Fi->database, Fi->driver);
+	
+	/* get column type as DB_C_TYPE_* */
+	coltype = db_column_Ctype(driver, Fi->table, dissolve_key);
+    }
+
+
     /* sort list */
     qsort(cats_array, ncats_array, sizeof(int), cmp);
 
@@ -342,7 +400,8 @@
 	    if (type == GV_BOUNDARY && (left_area || right_area)) {
 		if (!dissolve ||
 		    !areas_new_cats_match(In, left_area, right_area,
-					  type_only, field, new, reverse))
+					  type_only, field, new, reverse,
+					  dissolve_key, coltype, driver, Fi))
 		    write = 1;
 	    }
 	}
@@ -361,7 +420,8 @@
 		(left_field_match || right_field_match)) {
 		if (!dissolve ||
 		    !areas_new_cats_match(In, left_area, right_area,
-					  type_only, field, new, reverse))
+					  type_only, field, new, reverse,
+					  dissolve_key, coltype, driver, Fi))
 		    write = 1;
 	    }
 	}
@@ -381,7 +441,8 @@
 		(left_cat_match || right_cat_match)) {
 		if (!dissolve ||
 		    !areas_new_cats_match(In, left_area, right_area,
-					  type_only, field, new, reverse))
+					  type_only, field, new, reverse,
+					  dissolve_key, coltype, driver, Fi))
 		    write = 1;
 	    }
 	}
@@ -398,6 +459,9 @@
 	}
 
     }				/* end lines section */
-    
+
+    if (driver)
+	db_close_database_shutdown_driver(driver);
+
     return 0;
 }

Modified: grass/trunk/vector/v.extract/local_proto.h
===================================================================
--- grass/trunk/vector/v.extract/local_proto.h	2018-05-04 14:47:55 UTC (rev 72670)
+++ grass/trunk/vector/v.extract/local_proto.h	2018-05-04 17:14:59 UTC (rev 72671)
@@ -5,5 +5,5 @@
 /* extract.c */
 int cmp(const void *, const void *);
 int extract_line(int, int *, struct Map_info *,
-		 struct Map_info *, int, int, int,
+		 struct Map_info *, int, int, int, char* ,
 		 int, int, int);

Modified: grass/trunk/vector/v.extract/main.c
===================================================================
--- grass/trunk/vector/v.extract/main.c	2018-05-04 14:47:55 UTC (rev 72670)
+++ grass/trunk/vector/v.extract/main.c	2018-05-04 17:14:59 UTC (rev 72671)
@@ -52,7 +52,7 @@
     struct GModule *module;
     struct {
 	struct Option *input, *output, *file, *new, *type, *list,
-	    *field, *where, *nrand;
+	    *field, *where, *nrand, *d_key;
     } opt;
     struct {
 	struct Flag *t, *d, *r;
@@ -66,6 +66,7 @@
     struct Cat_index *ci;
     
     int ucat_count, *ucat_array, prnd, seed, nrandom, nfeatures;
+    char *dissolve_key;
 
     Fi = NULL;
     ucat_array = NULL;
@@ -144,6 +145,12 @@
     opt.new->description = _("If new >= 0, attributes is not copied");
     opt.new->guisection = _("Attributes");
     
+    opt.d_key = G_define_standard_option(G_OPT_DB_COLUMN);
+    opt.d_key->key = "dissolve_column";
+    opt.d_key->label = _("Name of attribute column for dissolving areas");
+    opt.d_key->description = _("Preserves category values");
+    opt.d_key->required = NO;
+
     if (G_parser(argc, argv))
 	exit(EXIT_FAILURE);
     
@@ -174,11 +181,6 @@
     Vect_check_input_output_name(input, output,
 				 G_FATAL_EXIT);
     
-    if (flag.d->answer)
-	dissolve = TRUE;
-    else
-	dissolve = FALSE;
-	
     if (!opt.new->answer)
 	new_cat = 0;
     else
@@ -197,6 +199,63 @@
 	type |= GV_CENTROID;
     }
 
+    dissolve_key = NULL;
+    if (flag.d->answer && 
+        ((type & GV_AREA) || ((type & GV_CENTROID) && (type & GV_BOUNDARY)))) {
+	dissolve = TRUE;
+	if (field > 0 && opt.d_key->answer) {
+	    int i, ncols, ret;
+	    dbTable *Table;
+	    dbColumn *Col;
+	    dbString tabname;
+
+	    dissolve_key = opt.d_key->answer;
+
+	    Fi = Vect_get_field(&In, field);
+	    if (!Fi) {
+		G_fatal_error(_("Database connection not defined for layer <%s>"),
+			      opt.field->answer);
+	    }
+
+	    G_verbose_message(_("Searching for column <%s> in table <%s>..."),
+	                      dissolve_key, Fi->table);
+
+	    driver = db_start_driver_open_database(Fi->driver, Fi->database);
+	    if (driver == NULL)
+		G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
+			      Fi->database, Fi->driver);
+
+	    db_init_string(&tabname);
+	    db_set_string(&tabname, Fi->table);
+
+	    if (db_describe_table(driver, &tabname, &Table) != DB_OK) {
+		G_fatal_error(_("Unable to describe table <%s>"), Fi->table);
+	    }
+
+	    ret = 0;
+
+	    ncols = db_get_table_number_of_columns(Table);
+	    G_debug(3, "ncol = %d", ncols);
+
+	    for (i = 0; i < ncols; i++) {
+		Col = db_get_table_column(Table, i);
+		if (G_strcasecmp(db_get_column_name(Col), dissolve_key) == 0) {
+		    ret = 1;
+		    break;
+		}
+	    }
+	    db_free_table(Table);
+	    db_free_string(&tabname);
+	    db_close_database_shutdown_driver(driver);
+	    
+	    if (!ret)
+		G_fatal_error(_("Column <%s> does not exist for layer %d"),
+		              dissolve_key, field);
+	}
+    }
+    else
+	dissolve = FALSE;
+	
     /* Read categoy list */
     cat_count = 0;
     if (opt.list->answer != NULL) {
@@ -359,8 +418,8 @@
 	Vect_copy_map_dblinks(&In, &Out, TRUE);
     }
 
-    extract_line(cat_count, cat_array, &In, &Out, new_cat, type, dissolve, field,
-		 type_only, flag.r->answer ? 1 : 0);
+    extract_line(cat_count, cat_array, &In, &Out, new_cat, type, 
+		 dissolve, dissolve_key, field, type_only, flag.r->answer ? 1 : 0);
 
     Vect_build(&Out);
 



More information about the grass-commit mailing list