|
@@ -4,19 +4,18 @@
|
|
|
* MODULE: v.extract
|
|
|
*
|
|
|
* AUTHOR(S): R.L.Glenn , Soil Conservation Service, USDA
|
|
|
- * update to 5.7: Radim Blazek
|
|
|
+ * Updated for 5.7 by Radim Blazek
|
|
|
+ * Updated for 7.0 by Martin Landa <landa.martin gmail.com>
|
|
|
*
|
|
|
- * PURPOSE: Provides a means of generating vector (digit) files
|
|
|
- * from an existing vector maplayer. Selects all vector
|
|
|
- * boundaries for 1 or several areas of a list of
|
|
|
- * user provided categories.
|
|
|
+ * PURPOSE: Selects vector features from an existing vector map and
|
|
|
+ * creates a new vector map containing only the selected
|
|
|
+ * features.
|
|
|
*
|
|
|
- * COPYRIGHT: (C) 2002-2009 by the GRASS Development Team
|
|
|
+ * COPYRIGHT: (C) 2002-2009, 2011 by the GRASS Development Team
|
|
|
*
|
|
|
- * This program is free software under the
|
|
|
- * GNU General Public License (>=v2).
|
|
|
- * Read the file COPYING that comes with GRASS
|
|
|
- * for details.
|
|
|
+ * This program is free software under the GNU General
|
|
|
+ * Public License (>=v2). Read the file COPYING that
|
|
|
+ * comes with GRASS for details.
|
|
|
*
|
|
|
* TODO: - fix white space problems for file= option
|
|
|
****************************************************************/
|
|
@@ -28,62 +27,50 @@
|
|
|
#include <search.h>
|
|
|
#include <sys/types.h>
|
|
|
#include <unistd.h>
|
|
|
+
|
|
|
#include <grass/gis.h>
|
|
|
#include <grass/vector.h>
|
|
|
#include <grass/dbmi.h>
|
|
|
#include <grass/gmath.h>
|
|
|
#include <grass/glocale.h>
|
|
|
|
|
|
-static int *cat_array, cat_count, cat_size;
|
|
|
-int scan_cats(char *, int *, int *);
|
|
|
-int xtract_line(int, int[], struct Map_info *, struct Map_info *, int, int,
|
|
|
- int, int, int, int);
|
|
|
-
|
|
|
-static void add_cat(int x)
|
|
|
-{
|
|
|
- G_debug(2, "add_cat %d", x);
|
|
|
-
|
|
|
- if (cat_count >= cat_size) {
|
|
|
- cat_size = (cat_size < 1000) ? 1000 : cat_size * 2;
|
|
|
- cat_array = G_realloc(cat_array, cat_size * sizeof(int));
|
|
|
- }
|
|
|
-
|
|
|
- cat_array[cat_count++] = x;
|
|
|
-}
|
|
|
+#include "local_proto.h"
|
|
|
|
|
|
-/* Comparison function for *search */
|
|
|
-static int cmp(const void *pa, const void *pb)
|
|
|
-{
|
|
|
- int *p1 = (int *)pa;
|
|
|
- int *p2 = (int *)pb;
|
|
|
+static int *cat_array, cat_count, cat_size;
|
|
|
|
|
|
- if (*p1 < *p2)
|
|
|
- return -1;
|
|
|
- if (*p1 > *p2)
|
|
|
- return 1;
|
|
|
- return 0;
|
|
|
-}
|
|
|
+static int scan_cats(char *, int *, int *);
|
|
|
+static void add_cat(int);
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
{
|
|
|
- int i, new_cat, type, ncats, *cats, c;
|
|
|
- int **ocats, *nocats, nfields, *fields;
|
|
|
- int field;
|
|
|
- int dissolve = 0, x, y, type_only;
|
|
|
+ int i, new_cat, type, ncats, *cats, c, is_ogr;
|
|
|
+ int field, dissolve, x, y, type_only;
|
|
|
char buffr[1024], text[80];
|
|
|
char *input, *output;
|
|
|
+
|
|
|
+ FILE *in;
|
|
|
+
|
|
|
struct GModule *module;
|
|
|
- struct Option *inopt, *outopt, *fileopt, *newopt, *typopt, *listopt,
|
|
|
- *fieldopt, *whereopt, *nrandopt;
|
|
|
- struct Flag *t_flag, *d_flag, *r_flag;
|
|
|
+ struct {
|
|
|
+ struct Option *input, *output, *file, *new, *type, *list,
|
|
|
+ *field, *where, *nrand;
|
|
|
+ } opt;
|
|
|
+ struct {
|
|
|
+ struct Flag *t, *d, *r;
|
|
|
+ } flag;
|
|
|
+
|
|
|
struct Map_info In, Out;
|
|
|
struct field_info *Fi;
|
|
|
- FILE *in;
|
|
|
+
|
|
|
dbDriver *driver;
|
|
|
- struct line_cats *Cats;
|
|
|
+
|
|
|
struct Cat_index *ci;
|
|
|
- int ucat_count, *ucat_array = NULL, prnd, seed, nrandom, nfeatures;
|
|
|
+
|
|
|
+ int ucat_count, *ucat_array, prnd, seed, nrandom, nfeatures;
|
|
|
|
|
|
+ Fi = NULL;
|
|
|
+ ucat_array = NULL;
|
|
|
+
|
|
|
G_gisinit(argv[0]);
|
|
|
|
|
|
/* set up the options and flags for the command line parser */
|
|
@@ -91,160 +78,159 @@ int main(int argc, char **argv)
|
|
|
G_add_keyword(_("vector"));
|
|
|
G_add_keyword(_("extract"));
|
|
|
module->description =
|
|
|
- _("Selects vector objects from an existing vector map and "
|
|
|
- "creates a new map containing only the selected objects.");
|
|
|
+ _("Selects vector features from an existing vector map and "
|
|
|
+ "creates a new vector map containing only the selected features.");
|
|
|
|
|
|
- d_flag = G_define_flag();
|
|
|
- d_flag->key = 'd';
|
|
|
- d_flag->description = _("Dissolve common boundaries (default is no)");
|
|
|
+ flag.d = G_define_flag();
|
|
|
+ flag.d->key = 'd';
|
|
|
+ flag.d->description = _("Dissolve common boundaries (default is no)");
|
|
|
|
|
|
- t_flag = G_define_flag();
|
|
|
- t_flag->key = 't';
|
|
|
- t_flag->description = _("Do not copy table (see also 'new' parameter)");
|
|
|
+ flag.t = G_define_flag();
|
|
|
+ flag.t->key = 't';
|
|
|
+ flag.t->description = _("Do not copy attributes (see also 'new' parameter)");
|
|
|
+ flag.t->guisection = _("Attributes");
|
|
|
|
|
|
- r_flag = G_define_flag();
|
|
|
- r_flag->key = 'r';
|
|
|
- r_flag->description = _("Reverse selection");
|
|
|
- r_flag->guisection = _("Selection");
|
|
|
+ flag.r = G_define_flag();
|
|
|
+ flag.r->key = 'r';
|
|
|
+ flag.r->description = _("Reverse selection");
|
|
|
+ flag.r->guisection = _("Selection");
|
|
|
|
|
|
- inopt = G_define_standard_option(G_OPT_V_INPUT);
|
|
|
+ opt.input = G_define_standard_option(G_OPT_V_INPUT);
|
|
|
|
|
|
- fieldopt = G_define_standard_option(G_OPT_V_FIELD);
|
|
|
- fieldopt->guisection = _("Selection");
|
|
|
+ opt.field = G_define_standard_option(G_OPT_V_FIELD);
|
|
|
+ opt.field->guisection = _("Selection");
|
|
|
|
|
|
- typopt = G_define_standard_option(G_OPT_V_TYPE);
|
|
|
- typopt->answer = "point,line,boundary,centroid,area,face";
|
|
|
- typopt->options = "point,line,boundary,centroid,area,face";
|
|
|
- typopt->label = _("Types to be extracted");
|
|
|
- typopt->guisection = _("Selection");
|
|
|
-
|
|
|
- listopt = G_define_standard_option(G_OPT_V_CATS);
|
|
|
- listopt->key = "list";
|
|
|
- listopt->guisection = _("Selection");
|
|
|
-
|
|
|
- whereopt = G_define_standard_option(G_OPT_DB_WHERE);
|
|
|
- whereopt->guisection = _("Selection");
|
|
|
+ opt.type = G_define_standard_option(G_OPT_V_TYPE);
|
|
|
+ opt.type->answer = "point,line,boundary,centroid,area,face";
|
|
|
+ opt.type->options = "point,line,boundary,centroid,area,face";
|
|
|
+ opt.type->label = _("Types to be extracted");
|
|
|
+ opt.type->guisection = _("Selection");
|
|
|
+
|
|
|
+ opt.list = G_define_standard_option(G_OPT_V_CATS);
|
|
|
+ opt.list->guisection = _("Selection");
|
|
|
+
|
|
|
+ opt.where = G_define_standard_option(G_OPT_DB_WHERE);
|
|
|
+ opt.where->guisection = _("Selection");
|
|
|
|
|
|
- outopt = G_define_standard_option(G_OPT_V_OUTPUT);
|
|
|
+ opt.output = G_define_standard_option(G_OPT_V_OUTPUT);
|
|
|
|
|
|
- fileopt = G_define_standard_option(G_OPT_F_INPUT);
|
|
|
- fileopt->key = "file";
|
|
|
- fileopt->required = NO;
|
|
|
- fileopt->label =
|
|
|
+ opt.file = G_define_standard_option(G_OPT_F_INPUT);
|
|
|
+ opt.file->key = "file";
|
|
|
+ opt.file->required = NO;
|
|
|
+ opt.file->label =
|
|
|
_("Input text file with category numbers/number ranges to be extracted");
|
|
|
- fileopt->description = _("If '-' given reads from standard input");
|
|
|
- fileopt->guisection = _("Selection");
|
|
|
-
|
|
|
- nrandopt = G_define_option();
|
|
|
- nrandopt->key = "random";
|
|
|
- nrandopt->type = TYPE_INTEGER;
|
|
|
- nrandopt->required = NO;
|
|
|
- nrandopt->label =
|
|
|
+ opt.file->description = _("If '-' given reads from standard input");
|
|
|
+ opt.file->guisection = _("Selection");
|
|
|
+
|
|
|
+ opt.nrand = G_define_option();
|
|
|
+ opt.nrand->key = "random";
|
|
|
+ opt.nrand->type = TYPE_INTEGER;
|
|
|
+ opt.nrand->required = NO;
|
|
|
+ opt.nrand->label =
|
|
|
_("Number of random categories matching vector objects to extract");
|
|
|
- nrandopt->description =
|
|
|
+ opt.nrand->description =
|
|
|
_("Number must be smaller than unique cat count in layer");
|
|
|
- nrandopt->guisection = _("Selection");
|
|
|
-
|
|
|
- newopt = G_define_option();
|
|
|
- newopt->key = "new";
|
|
|
- newopt->type = TYPE_INTEGER;
|
|
|
- newopt->required = NO;
|
|
|
- newopt->answer = "-1";
|
|
|
- newopt->label =
|
|
|
- _("Enter -1 to keep original categories or the desired NEW category value");
|
|
|
- newopt->description = _("If new >= 0, table is not copied");
|
|
|
+ opt.nrand->guisection = _("Selection");
|
|
|
+
|
|
|
+ opt.new = G_define_option();
|
|
|
+ opt.new->key = "new";
|
|
|
+ opt.new->type = TYPE_INTEGER;
|
|
|
+ opt.new->required = NO;
|
|
|
+ opt.new->answer = "-1";
|
|
|
+ opt.new->label = _("Desired new category value "
|
|
|
+ "(enter -1 to keep original categories)");
|
|
|
+ opt.new->description = _("If new >= 0, attributes is not copied");
|
|
|
+ opt.new->guisection = _("Attributes");
|
|
|
|
|
|
- /* heeeerrrrrre's the PARSER */
|
|
|
if (G_parser(argc, argv))
|
|
|
exit(EXIT_FAILURE);
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
/* start checking options and flags */
|
|
|
c = 0;
|
|
|
- if (fileopt->answer != NULL)
|
|
|
+ if (opt.file->answer != NULL)
|
|
|
c++;
|
|
|
- if (listopt->answers != NULL)
|
|
|
+ if (opt.list->answers != NULL)
|
|
|
c++;
|
|
|
- if (whereopt->answer != NULL)
|
|
|
+ if (opt.where->answer != NULL)
|
|
|
c++;
|
|
|
- if (nrandopt->answer != NULL)
|
|
|
+ if (opt.nrand->answer != NULL)
|
|
|
c++;
|
|
|
if (c > 1)
|
|
|
- G_fatal_error(_("List, file, where and random options are exclusive. "
|
|
|
- "Please specify only one of them"));
|
|
|
- c = 0;
|
|
|
-
|
|
|
- type_only = 0;
|
|
|
- if (!listopt->answers && !fileopt->answer && !whereopt->answer &&
|
|
|
- !nrandopt->answer) {
|
|
|
- type_only = 1;
|
|
|
+ G_fatal_error(_("Options <%s>, <%s>, <%s> and <%s> options are exclusive. "
|
|
|
+ "Please specify only one of them."),
|
|
|
+ opt.list->key, opt.file->key, opt.where->key,
|
|
|
+ opt.nrand->key);
|
|
|
+
|
|
|
+ type_only = FALSE;
|
|
|
+ if (!opt.list->answers && !opt.file->answer && !opt.where->answer &&
|
|
|
+ !opt.nrand->answer) {
|
|
|
+ type_only = TRUE;
|
|
|
}
|
|
|
|
|
|
- Vect_check_input_output_name(inopt->answer, outopt->answer,
|
|
|
+ input = opt.input->answer;
|
|
|
+ output = opt.output->answer;
|
|
|
+ Vect_check_input_output_name(input, output,
|
|
|
GV_FATAL_EXIT);
|
|
|
-
|
|
|
- /* set input vector map name and mapset */
|
|
|
- input = inopt->answer;
|
|
|
-
|
|
|
- /* set output vector map name */
|
|
|
- output = outopt->answer;
|
|
|
-
|
|
|
- if (d_flag->answer)
|
|
|
- dissolve = 1;
|
|
|
-
|
|
|
- if (!newopt->answer)
|
|
|
+
|
|
|
+ if (flag.d->answer)
|
|
|
+ dissolve = TRUE;
|
|
|
+ else
|
|
|
+ dissolve = FALSE;
|
|
|
+
|
|
|
+ if (!opt.new->answer)
|
|
|
new_cat = 0;
|
|
|
else
|
|
|
- new_cat = atoi(newopt->answer);
|
|
|
+ new_cat = atoi(opt.new->answer);
|
|
|
|
|
|
/* Do initial read of input file */
|
|
|
Vect_set_open_level(2); /* topology required */
|
|
|
- Vect_open_old2(&In, input, "", fieldopt->answer);
|
|
|
+ Vect_open_old2(&In, input, "", opt.field->answer);
|
|
|
|
|
|
- field = Vect_get_field_number(&In, fieldopt->answer);
|
|
|
+ field = Vect_get_field_number(&In, opt.field->answer);
|
|
|
|
|
|
- type = Vect_option_to_types(typopt);
|
|
|
+ type = Vect_option_to_types(opt.type);
|
|
|
if (type & GV_AREA) {
|
|
|
type |= GV_CENTROID;
|
|
|
}
|
|
|
|
|
|
/* Read categoy list */
|
|
|
cat_count = 0;
|
|
|
- if (listopt->answer != NULL) {
|
|
|
+ if (opt.list->answer != NULL) {
|
|
|
/* no file of categories to read, process cat list */
|
|
|
/* first check for valid list */
|
|
|
- for (i = 0; listopt->answers[i]; i++) {
|
|
|
- G_debug(2, "catlist item: %s", listopt->answers[i]);
|
|
|
- if (!scan_cats(listopt->answers[i], &x, &y))
|
|
|
+ for (i = 0; opt.list->answers[i]; i++) {
|
|
|
+ G_debug(2, "catlist item: %s", opt.list->answers[i]);
|
|
|
+ if (!scan_cats(opt.list->answers[i], &x, &y))
|
|
|
G_fatal_error(_("Category value in '%s' not valid"),
|
|
|
- listopt->answers[i]);
|
|
|
+ opt.list->answers[i]);
|
|
|
}
|
|
|
|
|
|
/* valid list, put into cat value array */
|
|
|
- for (i = 0; listopt->answers[i]; i++) {
|
|
|
- scan_cats(listopt->answers[i], &x, &y);
|
|
|
+ for (i = 0; opt.list->answers[i]; i++) {
|
|
|
+ scan_cats(opt.list->answers[i], &x, &y);
|
|
|
while (x <= y)
|
|
|
add_cat(x++);
|
|
|
}
|
|
|
}
|
|
|
- else if (fileopt->answer != NULL) { /* got a file of category numbers */
|
|
|
- if (G_strcasecmp(fileopt->answer, "-") == 0) {
|
|
|
+ else if (opt.file->answer != NULL) { /* got a file of category numbers */
|
|
|
+ if (strcmp(opt.file->answer, "-") == 0) {
|
|
|
in = stdin;
|
|
|
}
|
|
|
else {
|
|
|
- G_message(_("Process file <%s> for category numbers"),
|
|
|
- fileopt->answer);
|
|
|
+ G_verbose_message(_("Process file <%s> for category numbers..."),
|
|
|
+ opt.file->answer);
|
|
|
|
|
|
/* open input file */
|
|
|
- if ((in = fopen(fileopt->answer, "r")) == NULL)
|
|
|
+ if ((in = fopen(opt.file->answer, "r")) == NULL)
|
|
|
G_fatal_error(_("Unable to open specified file <%s>"),
|
|
|
- fileopt->answer);
|
|
|
+ opt.file->answer);
|
|
|
}
|
|
|
|
|
|
- while (1) {
|
|
|
+ while (TRUE) {
|
|
|
if (!fgets(buffr, 39, in))
|
|
|
break;
|
|
|
- G_chop(buffr); /* eliminate some white space, we accept numbers and dashes only */
|
|
|
+ /* eliminate some white space, we accept numbers and dashes only */
|
|
|
+ G_chop(buffr);
|
|
|
sscanf(buffr, "%[-0-9]", text);
|
|
|
if (strlen(text) == 0)
|
|
|
G_warning(_("Ignored text entry: %s"), buffr);
|
|
@@ -256,31 +242,30 @@ int main(int argc, char **argv)
|
|
|
add_cat(x++);
|
|
|
}
|
|
|
|
|
|
- if (G_strcasecmp(fileopt->answer, "-") != 0)
|
|
|
+ if (strcmp(opt.file->answer, "-") != 0)
|
|
|
fclose(in);
|
|
|
-
|
|
|
}
|
|
|
- else if (whereopt->answer != NULL) {
|
|
|
+ else if (opt.where->answer != NULL) {
|
|
|
Fi = Vect_get_field(&In, field);
|
|
|
if (!Fi) {
|
|
|
G_fatal_error(_("Database connection not defined for layer <%s>"),
|
|
|
- fieldopt->answer);
|
|
|
+ opt.field->answer);
|
|
|
}
|
|
|
|
|
|
- G_debug(1, "Loading categories from table <%s>", Fi->table);
|
|
|
+ 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);
|
|
|
|
|
|
- ncats = db_select_int(driver, Fi->table, Fi->key, whereopt->answer,
|
|
|
+ ncats = db_select_int(driver, Fi->table, Fi->key, opt.where->answer,
|
|
|
&cats);
|
|
|
if (ncats == -1)
|
|
|
- G_fatal_error(_("Unable select records from table <%s>"), Fi->table);
|
|
|
- G_message(_("%d categories loaded from table <%s>"), ncats,
|
|
|
- Fi->table);
|
|
|
-
|
|
|
+ G_fatal_error(_("Unable select records from table <%s>"),
|
|
|
+ Fi->table);
|
|
|
+ G_verbose_message(_("%d categories loaded"), ncats);
|
|
|
+
|
|
|
db_close_database(driver);
|
|
|
db_shutdown_driver(driver);
|
|
|
|
|
@@ -289,23 +274,23 @@ int main(int argc, char **argv)
|
|
|
if (ncats >= 0)
|
|
|
G_free(cats);
|
|
|
}
|
|
|
- else if (nrandopt->answer != NULL) { /* Generate random category list */
|
|
|
-
|
|
|
+ else if (opt.nrand->answer != NULL) { /* Generate random category list */
|
|
|
/* We operate on layer's CAT's and thus valid layer is required */
|
|
|
if (Vect_cidx_get_field_index(&In, field) < 0)
|
|
|
G_fatal_error(_("This map has no categories attached. "
|
|
|
- "Use v.category to attach categories to this vector map."));
|
|
|
+ "Use v.category to attach categories to "
|
|
|
+ "this vector map."));
|
|
|
|
|
|
/* Don't do any processing, if user input is wrong */
|
|
|
- nrandom = atoi(nrandopt->answer);
|
|
|
+ nrandom = atoi(opt.nrand->answer);
|
|
|
if (nrandom < 1)
|
|
|
G_fatal_error(_("Please specify random number larger than 0"));
|
|
|
|
|
|
nfeatures = Vect_cidx_get_type_count(&In, field, type);
|
|
|
if (nrandom >= nfeatures)
|
|
|
G_fatal_error(_("Random category count must be smaller than feature count. "
|
|
|
- "There are only %d features of type(s): %s"),
|
|
|
- nfeatures, typopt->answer);
|
|
|
+ "There are only %d features of type(s): %s"),
|
|
|
+ nfeatures, opt.type->answer);
|
|
|
|
|
|
/* Let's create an array of uniq CAT values
|
|
|
According to Vlib/build.c, cidx should be allready sorted by dig_cidx_sort() */
|
|
@@ -326,14 +311,14 @@ int main(int argc, char **argv)
|
|
|
}
|
|
|
|
|
|
if (nrandom >= ucat_count)
|
|
|
- G_fatal_error(_("Random category count is larger or equal to uniq \"%s\" feature category count %d"),
|
|
|
- typopt->answer, ucat_count);
|
|
|
+ G_fatal_error(_("Random category count is larger or equal to "
|
|
|
+ "uniq <%s> feature category count %d"),
|
|
|
+ opt.type->answer, ucat_count);
|
|
|
|
|
|
if (ucat_count >= RAND_MAX)
|
|
|
- G_fatal_error
|
|
|
- ("There are more categories than random number generator can reach. "
|
|
|
- "Report this as a GRASS bug.");
|
|
|
-
|
|
|
+ G_fatal_error(_("There are more categories than random number "
|
|
|
+ "generator can reach. Report this as a GRASS bug."));
|
|
|
+
|
|
|
seed = getpid();
|
|
|
/* Initialise random number generator */
|
|
|
G_math_rand(-1 * seed);
|
|
@@ -341,11 +326,11 @@ int main(int argc, char **argv)
|
|
|
/* Fill cat_array with list of valid random numbers */
|
|
|
while (cat_count < nrandom) {
|
|
|
/* Random number in range from 0 to largest CAT value */
|
|
|
- prnd =
|
|
|
- (int)floor(G_math_rand(seed) *
|
|
|
- (ucat_array[ucat_count - 1] + 1));
|
|
|
+ prnd = (int) floor(G_math_rand(seed) *
|
|
|
+ (ucat_array[ucat_count - 1] + 1));
|
|
|
qsort(cat_array, cat_count, sizeof(int), cmp);
|
|
|
- /* Check if generated number isn't already in final list and is in list of existing CATs */
|
|
|
+ /* Check if generated number isn't already in
|
|
|
+ final list and is in list of existing CATs */
|
|
|
if (bsearch(&prnd, cat_array, cat_count, sizeof(int), cmp) == NULL
|
|
|
&& bsearch(&prnd, ucat_array, ucat_count, sizeof(int),
|
|
|
cmp) != NULL)
|
|
@@ -355,7 +340,6 @@ int main(int argc, char **argv)
|
|
|
qsort(cat_array, cat_count, sizeof(int), cmp);
|
|
|
}
|
|
|
|
|
|
- /* Open output file only when it's required */
|
|
|
Vect_open_new(&Out, output, Vect_is_3d(&In));
|
|
|
Vect_hist_copy(&In, &Out);
|
|
|
Vect_hist_command(&Out);
|
|
@@ -364,116 +348,31 @@ int main(int argc, char **argv)
|
|
|
Vect_copy_head_data(&In, &Out);
|
|
|
|
|
|
G_message(_("Extracting features..."));
|
|
|
- xtract_line(cat_count, cat_array, &In, &Out, new_cat, type, dissolve, field,
|
|
|
- type_only, r_flag->answer ? 1 : 0);
|
|
|
+
|
|
|
+ is_ogr = Vect_maptype(&Out) == GV_FORMAT_OGR_DIRECT;
|
|
|
+ if (!flag.t->answer && is_ogr) {
|
|
|
+ /* Copy attributes for OGR output */
|
|
|
+ if (!Fi)
|
|
|
+ Fi = Vect_get_field(&In, field);
|
|
|
+ if (!Fi)
|
|
|
+ G_fatal_error(_("Database connection not defined for layer <%s>"),
|
|
|
+ opt.field->answer);
|
|
|
+ Vect_map_add_dblink(&Out, Fi->number, Fi->name, Fi->table, Fi->key,
|
|
|
+ Fi->database, Fi->driver);
|
|
|
+ }
|
|
|
+
|
|
|
+ extract_line(cat_count, cat_array, &In, &Out, new_cat, type, dissolve, field,
|
|
|
+ type_only, flag.r->answer ? 1 : 0);
|
|
|
|
|
|
Vect_build(&Out);
|
|
|
|
|
|
/* Copy tables */
|
|
|
- if (!t_flag->answer) {
|
|
|
- int nlines, line;
|
|
|
- int ttype, ntabs = 0;
|
|
|
- struct field_info *IFi, *OFi;
|
|
|
-
|
|
|
- /* Collect list of output cats */
|
|
|
- Cats = Vect_new_cats_struct();
|
|
|
- nfields = Vect_cidx_get_num_fields(&Out);
|
|
|
- ocats = (int **)G_malloc(nfields * sizeof(int *));
|
|
|
- nocats = (int *)G_malloc(nfields * sizeof(int));
|
|
|
- fields = (int *)G_malloc(nfields * sizeof(int));
|
|
|
- for (i = 0; i < nfields; i++) {
|
|
|
- nocats[i] = 0;
|
|
|
- ocats[i] =
|
|
|
- (int *)G_malloc(Vect_cidx_get_num_cats_by_index(&Out, i) *
|
|
|
- sizeof(int));
|
|
|
- fields[i] = Vect_cidx_get_field_number(&Out, i);
|
|
|
- }
|
|
|
-
|
|
|
- nlines = Vect_get_num_lines(&Out);
|
|
|
- for (line = 1; line <= nlines; line++) {
|
|
|
- Vect_read_line(&Out, NULL, Cats, line);
|
|
|
-
|
|
|
- for (i = 0; i < Cats->n_cats; i++) {
|
|
|
- int f, j;
|
|
|
-
|
|
|
- for (j = 0; j < nfields; j++) { /* find field */
|
|
|
- if (fields[j] == Cats->field[i]) {
|
|
|
- f = j;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- ocats[f][nocats[f]] = Cats->cat[i];
|
|
|
- nocats[f]++;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /* Copy tables */
|
|
|
- G_message(_("Writing attributes..."));
|
|
|
-
|
|
|
- /* Number of output tabs */
|
|
|
- for (i = 0; i < Vect_get_num_dblinks(&In); i++) {
|
|
|
- int j, f = -1;
|
|
|
-
|
|
|
- IFi = Vect_get_dblink(&In, i);
|
|
|
-
|
|
|
- for (j = 0; j < nfields; j++) { /* find field */
|
|
|
- if (fields[j] == IFi->number) {
|
|
|
- f = j;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- if (f >= 0 && nocats[f] > 0)
|
|
|
- ntabs++;
|
|
|
- }
|
|
|
-
|
|
|
- if (ntabs > 1)
|
|
|
- ttype = GV_MTABLE;
|
|
|
- else
|
|
|
- ttype = GV_1TABLE;
|
|
|
-
|
|
|
- for (i = 0; i < nfields; i++) {
|
|
|
- int ret;
|
|
|
-
|
|
|
- if (fields[i] == 0)
|
|
|
- continue;
|
|
|
- if (nocats[i] == 0)
|
|
|
- continue;
|
|
|
- if (fields[i] == atoi(fieldopt->answer) && new_cat != -1)
|
|
|
- continue;
|
|
|
-
|
|
|
- G_verbose_message(_("Layer %d"), fields[i]);
|
|
|
-
|
|
|
- /* Make a list of categories */
|
|
|
- IFi = Vect_get_field(&In, fields[i]);
|
|
|
- if (!IFi) { /* no table */
|
|
|
- G_verbose_message(_("No table"));
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- OFi =
|
|
|
- Vect_default_field_info(&Out, IFi->number, IFi->name, ttype);
|
|
|
-
|
|
|
- ret =
|
|
|
- db_copy_table_by_ints(IFi->driver, IFi->database, IFi->table,
|
|
|
- OFi->driver,
|
|
|
- Vect_subst_var(OFi->database, &Out),
|
|
|
- OFi->table, IFi->key, ocats[i],
|
|
|
- nocats[i]);
|
|
|
-
|
|
|
- if (ret == DB_FAILED) {
|
|
|
- G_warning(_("Unable to copy table"));
|
|
|
- }
|
|
|
- else {
|
|
|
- Vect_map_add_dblink(&Out, OFi->number, OFi->name, OFi->table,
|
|
|
- IFi->key, OFi->database, OFi->driver);
|
|
|
- }
|
|
|
- G_done_msg(" ");
|
|
|
- }
|
|
|
+ if (!flag.t->answer && !is_ogr) {
|
|
|
+ copy_tabs(&In, field, new_cat, &Out);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
Vect_close(&In);
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
/* remove duplicate centroids */
|
|
|
if (dissolve) {
|
|
|
int line, nlines, ltype, area;
|
|
@@ -497,13 +396,23 @@ int main(int argc, char **argv)
|
|
|
Vect_build_partial(&Out, GV_BUILD_NONE);
|
|
|
Vect_build(&Out);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
Vect_close(&Out);
|
|
|
-
|
|
|
+
|
|
|
exit(EXIT_SUCCESS);
|
|
|
}
|
|
|
|
|
|
+void add_cat(int x)
|
|
|
+{
|
|
|
+ G_debug(2, "add_cat %d", x);
|
|
|
+
|
|
|
+ if (cat_count >= cat_size) {
|
|
|
+ cat_size = (cat_size < 1000) ? 1000 : cat_size * 2;
|
|
|
+ cat_array = G_realloc(cat_array, cat_size * sizeof(int));
|
|
|
+ }
|
|
|
|
|
|
+ cat_array[cat_count++] = x;
|
|
|
+}
|
|
|
|
|
|
int scan_cats(char *s, int *x, int *y)
|
|
|
{
|