[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