Exemplo n.º 1
0
Arquivo: main.c Projeto: caomw/grass
int main(int argc, char *argv[])
{
    char *output, buf[DB_SQL_MAX];
    double (*rng)(void) = G_drand48;
    double zmin, zmax;
    int seed;
    int i, j, k, n, type, usefloat;
    int area, nareas, field;
    struct boxlist *List = NULL;
    BOX_SIZE *size_list = NULL;
    int alloc_size_list = 0;
    struct Map_info In, Out;
    struct line_pnts *Points;
    struct line_cats *Cats;
    struct cat_list *cat_list;
    struct bound_box box;
    struct Cell_head window;
    struct GModule *module;
    struct
    {
	struct Option *input, *field, *cats, *where, *output, *nsites,
		      *zmin, *zmax, *zcol, *ztype, *seed;
    } parm;
    struct
    {
	struct Flag *z, *notopo, *a;
    } flag;
    struct field_info *Fi;
    dbDriver *driver;
    dbTable *table;
    dbString sql;

    G_gisinit(argv[0]);

    module = G_define_module();
    G_add_keyword(_("vector"));
    G_add_keyword(_("sampling"));
    G_add_keyword(_("statistics"));
    G_add_keyword(_("random"));
    module->description = _("Generates random 2D/3D vector points.");

    parm.output = G_define_standard_option(G_OPT_V_OUTPUT);

    parm.nsites = G_define_option();
    parm.nsites->key = "n";
    parm.nsites->type = TYPE_INTEGER;
    parm.nsites->required = YES;
    parm.nsites->description = _("Number of points to be created");

    parm.input = G_define_standard_option(G_OPT_V_INPUT);
    parm.input->required = NO;
    parm.input->description = _("Restrict points to areas in input vector");
    parm.input->guisection = _("Selection");

    parm.field = G_define_standard_option(G_OPT_V_FIELD_ALL);
    parm.field->guisection = _("Selection");

    parm.cats = G_define_standard_option(G_OPT_V_CATS);
    parm.cats->guisection = _("Selection");
    
    parm.where = G_define_standard_option(G_OPT_DB_WHERE);
    parm.where->guisection = _("Selection");

    parm.zmin = G_define_option();
    parm.zmin->key = "zmin";
    parm.zmin->type = TYPE_DOUBLE;
    parm.zmin->required = NO;
    parm.zmin->description =
	_("Minimum z height (needs -z flag or column name)");
    parm.zmin->answer = "0.0";
    parm.zmin->guisection = _("3D output");

    parm.zmax = G_define_option();
    parm.zmax->key = "zmax";
    parm.zmax->type = TYPE_DOUBLE;
    parm.zmax->required = NO;
    parm.zmax->description =
	_("Maximum z height (needs -z flag or column name)");
    parm.zmax->answer = "0.0";
    parm.zmax->guisection = _("3D output");

    parm.seed = G_define_option();
    parm.seed->key = "seed";
    parm.seed->type = TYPE_INTEGER;
    parm.seed->required = NO;
    parm.seed->description =
	_("The seed to initialize the random generator. If not set the process ID is used");

    parm.zcol = G_define_standard_option(G_OPT_DB_COLUMN);
    parm.zcol->label = _("Name of column for z values");
    parm.zcol->description =
	_("Writes z values to column");
    parm.zcol->guisection = _("3D output");

    parm.ztype = G_define_option();
    parm.ztype->key = "column_type";
    parm.ztype->type = TYPE_STRING;
    parm.ztype->required = NO;
    parm.ztype->multiple = NO;
    parm.ztype->description = _("Type of column for z values");
    parm.ztype->options = "integer,double precision";
    parm.ztype->answer = "double precision";
    parm.ztype->guisection = _("3D output");

    flag.z = G_define_flag();
    flag.z->key = 'z';
    flag.z->description = _("Create 3D output");
    flag.z->guisection = _("3D output");

    flag.a = G_define_flag();
    flag.a->key = 'a';
    flag.a->description = _("Generate n points for each individual area");

    flag.notopo = G_define_standard_flag(G_FLG_V_TOPO);

    if (G_parser(argc, argv))
	exit(EXIT_FAILURE);

    output = parm.output->answer;
    n = atoi(parm.nsites->answer);
    
    if(parm.seed->answer)
        seed = atoi(parm.seed->answer);

    if (n <= 0) {
	G_fatal_error(_("Number of points must be > 0 (%d given)"), n);
    }

    nareas = 0;
    cat_list = NULL;
    field = -1;
    if (parm.input->answer) {
	Vect_set_open_level(2); /* topology required */
	if (2 > Vect_open_old2(&In, parm.input->answer, "", parm.field->answer))
	    G_fatal_error(_("Unable to open vector map <%s>"),
			  parm.input->answer);

	if (parm.field->answer)
	    field = Vect_get_field_number(&In, parm.field->answer);

	if ((parm.cats->answer || parm.where->answer) && field == -1) {
	    G_warning(_("Invalid layer number (%d). Parameter '%s' or '%s' specified, assuming layer '1'."),
		      field, parm.cats->key, parm.where->key);
	    field = 1;
	}
	if (field > 0)
	    cat_list = Vect_cats_set_constraint(&In, field, parm.where->answer,
						parm.cats->answer);
	nareas = Vect_get_num_areas(&In);
	if (nareas == 0) {
	    Vect_close(&In);
	    G_fatal_error(_("No areas in vector map <%s>"), parm.input->answer);
	}
    }
    else {
	if (flag.a->answer)
	    G_fatal_error(_("The <-%c> flag requires an input vector with areas"),
	                  flag.a->key);
    }

    /* create new vector map */
    if (-1 == Vect_open_new(&Out, output, flag.z->answer ? WITH_Z : WITHOUT_Z))
        G_fatal_error(_("Unable to create vector map <%s>"), output);
    Vect_set_error_handler_io(NULL, &Out);

    /* Do we need to write random values into attribute table? */
    usefloat = -1;
    if (parm.zcol->answer) {
	Fi = Vect_default_field_info(&Out, 1, NULL, GV_1TABLE);
	driver =
	    db_start_driver_open_database(Fi->driver,
					  Vect_subst_var(Fi->database, &Out));
	if (driver == NULL) {
	    G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
			  Vect_subst_var(Fi->database, &Out), Fi->driver);
	}
        db_set_error_handler_driver(driver);
        
	db_begin_transaction(driver);

	db_init_string(&sql);
	sprintf(buf, "create table %s (%s integer, %s %s)", Fi->table, GV_KEY_COLUMN,
		parm.zcol->answer, parm.ztype->answer);
	db_set_string(&sql, buf);
	Vect_map_add_dblink(&Out, 1, NULL, Fi->table, GV_KEY_COLUMN, Fi->database,
			    Fi->driver);

	/* Create table */
	G_debug(3, db_get_string(&sql));
	if (db_execute_immediate(driver, &sql) != DB_OK) {
	    G_fatal_error(_("Unable to create table: %s"),
			  db_get_string(&sql));
	}

	/* Create index */
	if (db_create_index2(driver, Fi->table, Fi->key) != DB_OK)
	    G_warning(_("Unable to create index"));

	/* Grant */
	if (db_grant_on_table
	    (driver, Fi->table, DB_PRIV_SELECT,
	     DB_GROUP | DB_PUBLIC) != DB_OK) {
	    G_fatal_error(_("Unable to grant privileges on table <%s>"),
			  Fi->table);
	}

	/* OK. Let's check what type of column user has created */
	db_set_string(&sql, Fi->table);
	if (db_describe_table(driver, &sql, &table) != DB_OK) {
	    G_fatal_error(_("Unable to describe table <%s>"), Fi->table);
	}

	if (db_get_table_number_of_columns(table) != 2) {
	    G_fatal_error(_("Table should contain only two columns"));
	}

	type = db_get_column_sqltype(db_get_table_column(table, 1));
	if (type == DB_SQL_TYPE_SMALLINT || type == DB_SQL_TYPE_INTEGER)
	    usefloat = 0;
	if (type == DB_SQL_TYPE_REAL || type == DB_SQL_TYPE_DOUBLE_PRECISION)
	    usefloat = 1;
	if (usefloat < 0) {
	    G_fatal_error(_("You have created unsupported column type. This module supports only INTEGER"
			   " and DOUBLE PRECISION column types."));
	}
    }

    Vect_hist_command(&Out);

    /* Init the random seed */
    if(parm.seed->answer)
	G_srand48(seed);
    else
	G_srand48_auto();

    G_get_window(&window);

    Points = Vect_new_line_struct();
    Cats = Vect_new_cats_struct();

    if (nareas > 0) {
	int first = 1, count;
	struct bound_box abox, bbox;

	box.W = window.west;
	box.E = window.east;
	box.S = window.south;
	box.N = window.north;
	box.B = -PORT_DOUBLE_MAX;
	box.T = PORT_DOUBLE_MAX;

	count = 0;

	for (i = 1; i <= nareas; i++) {
	    
	    if (!Vect_get_area_centroid(&In, i))
		continue;

	    if (field > 0) {
		if (Vect_get_area_cats(&In, i, Cats))
		    continue;

		if (!Vect_cats_in_constraint(Cats, field, cat_list))
		    continue;
	    }

	    Vect_get_area_box(&In, i, &abox);
	    if (!Vect_box_overlap(&abox, &box))
		continue;

	    if (first) {
		Vect_box_copy(&bbox, &abox);
		first = 0;
	    }
	    else
		Vect_box_extend(&bbox, &abox);
	    count++;
	}
	if (count == 0) {
	    Vect_close(&In);
	    Vect_close(&Out);
	    Vect_delete(output);
	    G_fatal_error(_("Selected areas in input vector <%s> do not overlap with the current region"),
			  parm.input->answer);
	}
	Vect_box_copy(&box, &bbox);

	/* does the vector overlap with the current region ? */
	if (box.W >= window.east || box.E <= window.west ||
	    box.S >= window.north || box.N <= window.south) {

	    Vect_close(&In);
	    Vect_close(&Out);
	    Vect_delete(output);
	    G_fatal_error(_("Input vector <%s> does not overlap with the current region"),
	                  parm.input->answer);
	}

	/* try to reduce the current region */
	if (window.east > box.E)
	    window.east = box.E;
	if (window.west < box.W)
	    window.west = box.W;
	if (window.north > box.N)
	    window.north = box.N;
	if (window.south < box.S)
	    window.south = box.S;

	List = Vect_new_boxlist(1);
	alloc_size_list = 10;
	size_list = G_malloc(alloc_size_list * sizeof(BOX_SIZE));
    }

    zmin = zmax = 0;
    if (flag.z->answer || parm.zcol->answer) {
	zmax = atof(parm.zmax->answer);
	zmin = atof(parm.zmin->answer);
    }

    G_message(_("Generating points..."));
    if (flag.a->answer && nareas > 0) {
	struct bound_box abox, bbox;
	int cat = 1;

	/* n points for each area */
	nareas = Vect_get_num_areas(&In);
	
	G_percent(0, nareas, 1);
	for (area = 1; area <= nareas; area++) {

	    G_percent(area, nareas, 1);

	    if (!Vect_get_area_centroid(&In, area))
		continue;

	    if (field > 0) {
		if (Vect_get_area_cats(&In, area, Cats))
		    continue;

		if (!Vect_cats_in_constraint(Cats, field, cat_list)) {
		    continue;
		}
	    }

	    box.W = window.west;
	    box.E = window.east;
	    box.S = window.south;
	    box.N = window.north;
	    box.B = -PORT_DOUBLE_MAX;
	    box.T = PORT_DOUBLE_MAX;
	    
	    Vect_get_area_box(&In, area, &abox);
	    if (!Vect_box_overlap(&box, &abox))
		continue;
		
	    bbox = abox;
	    if (bbox.W < box.W)
		bbox.W = box.W;
	    if (bbox.E > box.E)
		bbox.E = box.E;
	    if (bbox.S < box.S)
		bbox.S = box.S;
	    if (bbox.N > box.N)
		bbox.N = box.N;

	    for (i = 0; i < n; ++i) {
		double x, y, z;
		int outside = 1;
		int ret;

		Vect_reset_line(Points);
		Vect_reset_cats(Cats);

		while (outside) {
		    x = rng() * (bbox.W - bbox.E) + bbox.E;
		    y = rng() * (bbox.N - bbox.S) + bbox.S;
		    z = rng() * (zmax - zmin) + zmin;

		    ret = Vect_point_in_area(x, y, &In, area, &abox);

		    G_debug(3, "    area = %d Vect_point_in_area() = %d", area, ret);

		    if (ret >= 1) {
			outside = 0;
		    }
		}

		if (flag.z->answer)
		    Vect_append_point(Points, x, y, z);
		else
		    Vect_append_point(Points, x, y, 0.0);

		if (parm.zcol->answer) {
		    sprintf(buf, "insert into %s values ( %d, ", Fi->table, i + 1);
		    db_set_string(&sql, buf);
		    /* Round random value if column is integer type */
		    if (usefloat)
			sprintf(buf, "%f )", z);
		    else
			sprintf(buf, "%.0f )", z);
		    db_append_string(&sql, buf);

		    G_debug(3, db_get_string(&sql));
		    if (db_execute_immediate(driver, &sql) != DB_OK) {
			G_fatal_error(_("Cannot insert new row: %s"),
				      db_get_string(&sql));
		    }
		}

		Vect_cat_set(Cats, 1, cat++);
		Vect_write_line(&Out, GV_POINT, Points, Cats);
	    }
	}
    }
    else {
	/* n points in total */
	for (i = 0; i < n; ++i) {
	    double x, y, z;

	    G_percent(i, n, 4);

	    Vect_reset_line(Points);
	    Vect_reset_cats(Cats);

	    x = rng() * (window.west - window.east) + window.east;
	    y = rng() * (window.north - window.south) + window.south;
	    z = rng() * (zmax - zmin) + zmin;
	    
	    if (nareas) {
		int outside = 1;

		do {
		    /* select areas by box */
		    box.E = x;
		    box.W = x;
		    box.N = y;
		    box.S = y;
		    box.T = PORT_DOUBLE_MAX;
		    box.B = -PORT_DOUBLE_MAX;
		    Vect_select_areas_by_box(&In, &box, List);
		    G_debug(3, "  %d areas selected by box", List->n_values);

		    /* sort areas by size, the smallest is likely to be the nearest */
		    if (alloc_size_list < List->n_values) {
			alloc_size_list = List->n_values;
			size_list = G_realloc(size_list, alloc_size_list * sizeof(BOX_SIZE));
		    }

		    k = 0;
		    for (j = 0; j < List->n_values; j++) {
			area = List->id[j];

			if (!Vect_get_area_centroid(&In, area))
			    continue;

			if (field > 0) {
			    if (Vect_get_area_cats(&In, area, Cats))
				continue;

			    if (!Vect_cats_in_constraint(Cats, field, cat_list)) {
				continue;
			    }
			}

			List->id[k] = List->id[j];
			List->box[k] = List->box[j];
			size_list[k].i = List->id[k];
			box = List->box[k];
			size_list[k].box = List->box[k];
			size_list[k].size = (box.N - box.S) * (box.E - box.W);
			k++;
		    }
		    List->n_values = k;
		    
		    if (List->n_values == 2) {
			/* simple swap */
			if (size_list[1].size < size_list[0].size) {
			    size_list[0].i = List->id[1];
			    size_list[1].i = List->id[0];
			    size_list[0].box = List->box[1];
			    size_list[1].box = List->box[0];
			}
		    }
		    else if (List->n_values > 2)
			qsort(size_list, List->n_values, sizeof(BOX_SIZE), sort_by_size);

		    for (j = 0; j < List->n_values; j++) {
			int ret;

			area = size_list[j].i;
			ret = Vect_point_in_area(x, y, &In, area, &size_list[j].box);

			G_debug(3, "    area = %d Vect_point_in_area() = %d", area, ret);

			if (ret >= 1) {
			    outside = 0;
			    break;
			}
		    }
		    if (outside) {
			x = rng() * (window.west - window.east) + window.east;
			y = rng() * (window.north - window.south) + window.south;
			z = rng() * (zmax - zmin) + zmin;
		    }
		} while (outside);
	    }

	    if (flag.z->answer)
		Vect_append_point(Points, x, y, z);
	    else
		Vect_append_point(Points, x, y, 0.0);

	    if (parm.zcol->answer) {
		sprintf(buf, "insert into %s values ( %d, ", Fi->table, i + 1);
		db_set_string(&sql, buf);
		/* Round random value if column is integer type */
		if (usefloat)
		    sprintf(buf, "%f )", z);
		else
		    sprintf(buf, "%.0f )", z);
		db_append_string(&sql, buf);

		G_debug(3, db_get_string(&sql));
		if (db_execute_immediate(driver, &sql) != DB_OK) {
		    G_fatal_error(_("Cannot insert new row: %s"),
				  db_get_string(&sql));
		}
	    }

	    Vect_cat_set(Cats, 1, i + 1);
	    Vect_write_line(&Out, GV_POINT, Points, Cats);
	}
	G_percent(1, 1, 1);
    }
    
    if (parm.zcol->answer) {
	db_commit_transaction(driver);
	db_close_database_shutdown_driver(driver);
    }

    if (!flag.notopo->answer) {
	Vect_build(&Out);
    }
    Vect_close(&Out);

    exit(EXIT_SUCCESS);
}
Exemplo n.º 2
0
int main(int argc, char *argv[])
{
    int i, iopt;
    int operator;
    int aline, nalines, nskipped;
    int ltype, itype[2], ifield[2];
    int **cats, *ncats, nfields, *fields;
    char *mapset[2], *pre[2];
    struct GModule *module;
    struct GParm parm;
    struct GFlag flag;
    struct Map_info In[2], Out;
    struct field_info *IFi, *OFi;
    struct line_pnts *APoints, *BPoints;
    struct line_cats *ACats, *BCats;
    int *ALines;		/* List of lines: 0 do not output, 1 - write to output */
    struct ilist *List, *TmpList, *BoundList;

    G_gisinit(argv[0]);

    pre[0] = "a";
    pre[1] = "b";

    module = G_define_module();
    module->keywords = _("vector, spatial query");
    module->description =
	_("Selects features from vector map (A) by features from other vector map (B).");

    parse_options(&parm, &flag);
    
    if (G_parser(argc, argv))
	exit(EXIT_FAILURE);
    
    if (parm.operator->answer[0] == 'e')
	operator = OP_EQUALS;
    else if (parm.operator->answer[0] == 'd') {
	/* operator = OP_DISJOINT; */
	operator = OP_INTERSECTS;
	flag.reverse->answer = YES;
    }
    else if (parm.operator->answer[0] == 'i')
	operator = OP_INTERSECTS;
    else if (parm.operator->answer[0] == 't')
	operator = OP_TOUCHES;
    else if (parm.operator->answer[0] == 'c' && parm.operator->answer[1] == 'r')
	operator = OP_CROSSES;
    else if (parm.operator->answer[0] == 'w')
	operator = OP_WITHIN;
    else if (parm.operator->answer[0] == 'c' && parm.operator->answer[1] == 'o')
	operator = OP_CONTAINS;
    else if (parm.operator->answer[0] == 'o') {
	if (strcmp(parm.operator->answer, "overlaps") == 0)
	    operator = OP_OVERLAPS;
	else
	    operator = OP_OVERLAP;
    }
    else if (parm.operator->answer[0] == 'r')
	operator = OP_RELATE;
    else
	G_fatal_error(_("Unknown operator"));
    
    if (operator == OP_RELATE && !parm.relate->answer) {
	G_fatal_error(_("Required parameter <%s> not set"),
		      parm.relate->key);
    }
    
    for (iopt = 0; iopt < 2; iopt++) {
	itype[iopt] = Vect_option_to_types(parm.type[iopt]);
	ifield[iopt] = atoi(parm.field[iopt]->answer);

	Vect_check_input_output_name(parm.input[iopt]->answer, parm.output->answer,
				     GV_FATAL_EXIT);

	if ((mapset[iopt] =
	     G_find_vector2(parm.input[iopt]->answer, NULL)) == NULL) {
	    G_fatal_error(_("Vector map <%s> not found"),
			  parm.input[iopt]->answer);
	}
	
	Vect_set_open_level(2);
	Vect_open_old(&(In[iopt]), parm.input[iopt]->answer, mapset[iopt]);
    }
    
    /* Read field info */
    IFi = Vect_get_field(&(In[0]), ifield[0]);

    APoints = Vect_new_line_struct();
    BPoints = Vect_new_line_struct();
    ACats = Vect_new_cats_struct();
    BCats = Vect_new_cats_struct();
    List = Vect_new_list();
    TmpList = Vect_new_list();
    BoundList = Vect_new_list();

    /* Open output */
    Vect_open_new(&Out, parm.output->answer, Vect_is_3d(&(In[0])));
    Vect_set_map_name(&Out, _("Output from v.select"));
    Vect_set_person(&Out, G_whoami());
    Vect_copy_head_data(&(In[0]), &Out);
    Vect_hist_copy(&(In[0]), &Out);
    Vect_hist_command(&Out);

    nskipped = 0;
    nalines = Vect_get_num_lines(&(In[0]));

#ifdef HAVE_GEOS
    initGEOS(G_message, G_fatal_error);
    GEOSGeometry *AGeom = NULL;
#else
    void *AGeom = NULL;
#endif

    /* Alloc space for input lines array */
    ALines = (int *)G_calloc(nalines + 1, sizeof(int));

    G_message(_("Building spatial index..."));
    Vect_build_spatial_index(&In[0]);
    Vect_build_spatial_index(&In[1]);
    
    /* Lines in A. Go through all lines and mark those that meets condition */
    if (itype[0] & (GV_POINTS | GV_LINES)) {
	G_message(_("Processing features..."));
	
	for (aline = 1; aline <= nalines; aline++) {
	    BOUND_BOX abox;

	    G_debug(3, "aline = %d", aline);
	    G_percent(aline, nalines, 2);	/* must be before any continue */

	    /* Check category */
	    if (!flag.cat->answer && Vect_get_line_cat(&(In[0]), aline, ifield[0]) < 0) {
		nskipped++;
		continue;
	    }

	    /* Read line and check type */
	    if (operator != OP_OVERLAP) {
#ifdef HAVE_GEOS
		AGeom = Vect_read_line_geos(&(In[0]), aline, &ltype);
#endif
		if (!(ltype & (GV_POINT | GV_LINE)))
		    continue;

		if (!AGeom)
		    G_fatal_error(_("Unable to read line id %d from vector map <%s>"),
				  aline, Vect_get_full_name(&(In[0])));
	    }
	    else {
		ltype = Vect_read_line(&(In[0]), APoints, NULL, aline);
	    }
	    
	    if (!(ltype & itype[0]))
		continue;
	    
	    Vect_get_line_box(&(In[0]), aline, &abox);
	    abox.T = PORT_DOUBLE_MAX;
	    abox.B = -PORT_DOUBLE_MAX;

	    /* Check if this line overlaps any feature in B */
	    /* x Lines in B */
	    if (itype[1] & (GV_POINTS | GV_LINES)) {
		int i;
		int found = 0;
		
		/* Lines */
		Vect_select_lines_by_box(&(In[1]), &abox, itype[1], List);
		for (i = 0; i < List->n_values; i++) {
		    int bline;
		    
		    bline = List->value[i];
		    G_debug(3, "  bline = %d", bline);
		    
		    /* Check category */
		    if (!flag.cat->answer && Vect_get_line_cat(&(In[1]), bline, ifield[1]) < 0) {
			nskipped++;
			continue;
		    }
		    
		    if (operator != OP_OVERLAP) {
#ifdef HAVE_GEOS
			if(line_relate_geos(&(In[1]), AGeom,
					    bline, operator, parm.relate->answer)) {

			    found = 1;
			    break;
			}
#endif
		    }
		    else {
			Vect_read_line(&(In[1]), BPoints, NULL, bline);

			if (Vect_line_check_intersection(APoints, BPoints, 0)) {
			    found = 1;
			    break;
			}
		    }
		}
		
		if (found) {
		    ALines[aline] = 1;
		    continue;	/* Go to next A line */
		}
	    }
	    
	    /* x Areas in B. */
	    if (itype[1] & GV_AREA) {
		int i;
		
		Vect_select_areas_by_box(&(In[1]), &abox, List);
		for (i = 0; i < List->n_values; i++) {
		    int barea;
		    
		    barea = List->value[i];
		    G_debug(3, "  barea = %d", barea);
		    
		    if (Vect_get_area_cat(&(In[1]), barea, ifield[1]) < 0) {
			nskipped++;
			continue;
		    }

		    if (operator != OP_OVERLAP) {
#ifdef HAVE_GEOS
			if(area_relate_geos(&(In[1]), AGeom,
					    barea, operator, parm.relate->answer)) {
			    ALines[aline] = 1;
			    break;
			}
#endif
		    }
		    else {
			if (line_overlap_area(&(In[0]), aline, &(In[1]), barea)) {
			    ALines[aline] = 1;
			    break;
			}
		    }
		}
	    }
	    if (operator != OP_OVERLAP) {
#ifdef HAVE_GEOS
		GEOSGeom_destroy(AGeom);
#endif
		AGeom = NULL;
	    }
	}
    }
    
    /* Areas in A. */
    if (itype[0] & GV_AREA) {
	int aarea, naareas;

	G_message(_("Processing areas..."));
	
	naareas = Vect_get_num_areas(&(In[0]));

	for (aarea = 1; aarea <= naareas; aarea++) {
	    BOUND_BOX abox;

	    G_percent(aarea, naareas, 2);	/* must be before any continue */

	    if (Vect_get_area_cat(&(In[0]), aarea, ifield[0]) < 0) {
		nskipped++;
		continue;
	    }
	
	    Vect_get_area_box(&(In[0]), aarea, &abox);
	    abox.T = PORT_DOUBLE_MAX;
	    abox.B = -PORT_DOUBLE_MAX;

	    if (operator != OP_OVERLAP) {
#ifdef HAVE_GEOS
		AGeom = Vect_read_area_geos(&(In[0]), aarea);
#endif
		if (!AGeom)
		    G_fatal_error(_("Unable to read area id %d from vector map <%s>"),
				  aline, Vect_get_full_name(&(In[0])));
	    }

	    /* x Lines in B */
	    if (itype[1] & (GV_POINTS | GV_LINES)) {
		Vect_select_lines_by_box(&(In[1]), &abox, itype[1], List);

		for (i = 0; i < List->n_values; i++) {
		    int bline;

		    bline = List->value[i];

		    if (!flag.cat->answer && Vect_get_line_cat(&(In[1]), bline, ifield[1]) < 0) {
			nskipped++;
			continue;
		    }
		    
		    if (operator != OP_OVERLAP) {
#ifdef HAVE_GEOS
			if(line_relate_geos(&(In[1]), AGeom,
					    bline, operator, parm.relate->answer)) {
			    add_aarea(&(In[0]), aarea, ALines);
			    break;
			}
#endif
		    }
		    else {
			if (line_overlap_area(&(In[1]), bline, &(In[0]), aarea)) {
			    add_aarea(&(In[0]), aarea, ALines);
			    continue;
			}
		    }
		}
	    }

	    /* x Areas in B */
	    if (itype[1] & GV_AREA) {
		int naisles;
		int found = 0;

		/* List of areas B */

		/* Make a list of features forming area A */
		Vect_reset_list(List);

		Vect_get_area_boundaries(&(In[0]), aarea, BoundList);
		for (i = 0; i < BoundList->n_values; i++) {
		    Vect_list_append(List, abs(BoundList->value[i]));
		}

		naisles = Vect_get_area_num_isles(&(In[0]), aarea);

		for (i = 0; i < naisles; i++) {
		    int j, aisle;

		    aisle = Vect_get_area_isle(&(In[0]), aarea, i);

		    Vect_get_isle_boundaries(&(In[0]), aisle, BoundList);
		    for (j = 0; j < BoundList->n_values; j++) {
			Vect_list_append(List, BoundList->value[j]);
		    }
		}

		Vect_select_areas_by_box(&(In[1]), &abox, TmpList);

		for (i = 0; i < List->n_values; i++) {
		    int j, aline;

		    aline = abs(List->value[i]);

		    for (j = 0; j < TmpList->n_values; j++) {
			int barea, bcentroid;

			barea = TmpList->value[j];
			G_debug(3, "  barea = %d", barea);

			if (Vect_get_area_cat(&(In[1]), barea, ifield[1]) < 0) {
			    nskipped++;
			    continue;
			}

			/* Check if any centroid of area B is in area A.
			 * This test is important in if area B is completely within area A */
			bcentroid = Vect_get_area_centroid(&(In[1]), barea);
			Vect_read_line(&(In[1]), BPoints, NULL, bcentroid);

			if (operator != OP_OVERLAP) {
#ifdef HAVE_GEOS
			    if(area_relate_geos(&(In[1]), AGeom,
						barea, operator, parm.relate->answer)) {
				found = 1;
				break;
			    }
#endif
			}
			else {
			    if (Vect_point_in_area(&(In[0]), aarea,
						   BPoints->x[0], BPoints->y[0])) {
				found = 1;
				break;
			    }
			    
			    /* Check intersectin of lines from List with area B */
			    if (line_overlap_area(&(In[0]), aline,
						  &(In[1]), barea)) {
				found = 1;
				break;
			    }
			}
		    }
		    if (found) {
			add_aarea(&(In[0]), aarea, ALines);
			break;
		    }
		}
	    }
	    if (operator != OP_OVERLAP) {
#ifdef HAVE_GEOS
		GEOSGeom_destroy(AGeom);
#endif
		AGeom = NULL;
	    }
	}
    }
    
    Vect_close(&(In[1]));

#ifdef HAVE_GEOS
    finishGEOS();
#endif

    /* Write lines */
    nfields = Vect_cidx_get_num_fields(&(In[0]));
    cats = (int **)G_malloc(nfields * sizeof(int *));
    ncats = (int *)G_malloc(nfields * sizeof(int));
    fields = (int *)G_malloc(nfields * sizeof(int));
    for (i = 0; i < nfields; i++) {
	ncats[i] = 0;
	cats[i] =
	    (int *)G_malloc(Vect_cidx_get_num_cats_by_index(&(In[0]), i) *
			    sizeof(int));
	fields[i] = Vect_cidx_get_field_number(&(In[0]), i);
    }

    G_message(_("Writing selected features..."));
    for (aline = 1; aline <= nalines; aline++) {
	int atype;

	G_debug(4, "aline = %d ALines[aline] = %d", aline, ALines[aline]);
	G_percent(aline, nalines, 2);
	
	if ((!flag.reverse->answer && !(ALines[aline])) ||
	    (flag.reverse->answer && ALines[aline]))
	    continue;

	atype = Vect_read_line(&(In[0]), APoints, ACats, aline);
	Vect_write_line(&Out, atype, APoints, ACats);

	if (!(flag.table->answer) && (IFi != NULL)) {
	    for (i = 0; i < ACats->n_cats; i++) {
		int f, j;

		for (j = 0; j < nfields; j++) {	/* find field */
		    if (fields[j] == ACats->field[i]) {
			f = j;
			break;
		    }
		}
		cats[f][ncats[f]] = ACats->cat[i];
		ncats[f]++;
	    }
	}
    }

    /* Copy tables */
    if (!(flag.table->answer)) {
	int ttype, ntabs = 0;

	G_message(_("Writing attributes..."));

	/* Number of output tabs */
	for (i = 0; i < Vect_get_num_dblinks(&(In[0])); i++) {
	    int f, j;

	    IFi = Vect_get_dblink(&(In[0]), i);

	    for (j = 0; j < nfields; j++) {	/* find field */
		if (fields[j] == IFi->number) {
		    f = j;
		    break;
		}
	    }
	    if (ncats[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;

	    /* Make a list of categories */
	    IFi = Vect_get_field(&(In[0]), fields[i]);
	    if (!IFi) {		/* no table */
		G_warning(_("Layer %d - no table"), fields[i]);
		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, cats[i],
				      ncats[i]);

	    if (ret == DB_FAILED) {
		G_warning(_("Layer %d - unable to copy table"), fields[i]);
	    }
	    else {
		Vect_map_add_dblink(&Out, OFi->number, OFi->name, OFi->table,
				    IFi->key, OFi->database, OFi->driver);
	    }
	}
    }

    Vect_close(&(In[0]));

    Vect_build(&Out);
    Vect_close(&Out);

    if (nskipped > 0) {
      G_warning(_("%d features without category skipped"), nskipped);
    }

    G_done_msg(_("%d features written to output."), Vect_get_num_lines(&Out));

    exit(EXIT_SUCCESS);
}
Exemplo n.º 3
0
int main(int argc, char *argv[])
{
    char *p;
    int i, j, k;
    int method, half, use_catno;
    const char *mapset;
    struct GModule *module;
    struct Option *point_opt,	/* point vector */
     *area_opt,			/* area vector */
     *point_type_opt,		/* point type */
     *point_field_opt,		/* point layer */
     *area_field_opt,		/* area layer */
     *method_opt,		/* stats method */
     *point_column_opt,		/* point column for stats */
     *count_column_opt,		/* area column for point count */
     *stats_column_opt,		/* area column for stats result */
     *fs_opt;			/* field separator for printed output */
    struct Flag *print_flag;
    char fs[2];
    struct Map_info PIn, AIn;
    int point_type, point_field, area_field;
    struct line_pnts *Points;
    struct line_cats *ACats, *PCats;
    AREA_CAT *Area_cat;
    int pline, ptype, count;
    int area, nareas, nacats, nacatsalloc;
    int ctype, nrec;
    struct field_info *PFi, *AFi;
    dbString stmt;
    dbDriver *Pdriver, *Adriver;
    char buf[2000];
    int update_ok, update_err;
    struct boxlist *List;
    struct bound_box box;
    dbCatValArray cvarr;
    dbColumn *column;
    struct pvalcat
    {
	double dval;
	int catno;
    } *pvalcats;
    int npvalcats, npvalcatsalloc;
    stat_func *statsvalue = NULL;
    double result;

    column = NULL;

    G_gisinit(argv[0]);

    module = G_define_module();
    G_add_keyword(_("vector"));
    G_add_keyword(_("database"));
    G_add_keyword(_("attribute table"));
    module->description = _("Count points in areas, calculate statistics from point attributes.");

    point_opt = G_define_standard_option(G_OPT_V_INPUT);
    point_opt->key = "points";
    point_opt->description = _("Name of existing vector map with points");
    /* point_opt->guisection = _("Required"); */

    area_opt = G_define_standard_option(G_OPT_V_INPUT);
    area_opt->key = "areas";
    area_opt->description = _("Name of existing vector map with areas");
    /* area_opt->guisection = _("Required"); */

    point_type_opt = G_define_standard_option(G_OPT_V_TYPE);
    point_type_opt->key = "type";
    point_type_opt->options = "point,centroid";
    point_type_opt->answer = "point";
    point_type_opt->label = _("Feature type");
    point_type_opt->required = NO;

    point_field_opt = G_define_standard_option(G_OPT_V_FIELD);
    point_field_opt->key = "player";
    point_field_opt->label = _("Layer number for points map");

    area_field_opt = G_define_standard_option(G_OPT_V_FIELD);
    area_field_opt->key = "alayer";
    area_field_opt->label = _("Layer number for area map");

    method_opt = G_define_option();
    method_opt->key = "method";
    method_opt->type = TYPE_STRING;
    method_opt->required = NO;
    method_opt->multiple = NO;
    p = G_malloc(1024);
    for (i = 0; menu[i].name; i++) {
	if (i)
	    strcat(p, ",");
	else
	    *p = 0;
	strcat(p, menu[i].name);
    }
    method_opt->options = p;
    method_opt->description = _("Method for aggregate statistics");

    point_column_opt = G_define_standard_option(G_OPT_DB_COLUMN);
    point_column_opt->key = "pcolumn";
    point_column_opt->required = NO;
    point_column_opt->multiple = NO;
    point_column_opt->label =
	_("Column name of points map to use for statistics");
    point_column_opt->description = _("Column of points map must be numeric");

    count_column_opt = G_define_option();
    count_column_opt->key = "ccolumn";
    count_column_opt->type = TYPE_STRING;
    count_column_opt->required = NO;
    count_column_opt->multiple = NO;
    count_column_opt->label = _("Column name to upload points count");
    count_column_opt->description =
	_("Column to hold points count, must be of type integer, will be created if not existing");

    stats_column_opt = G_define_option();
    stats_column_opt->key = "scolumn";
    stats_column_opt->type = TYPE_STRING;
    stats_column_opt->required = NO;
    stats_column_opt->multiple = NO;
    stats_column_opt->label = _("Column name to upload statistics");
    stats_column_opt->description =
	_("Column to hold statistics, must be of type double, will be created if not existing");

    fs_opt = G_define_standard_option(G_OPT_F_SEP);
    fs_opt->answer = "|";
    fs_opt->key_desc = "character|space|tab";
    fs_opt->description = _("Output field separator");

    print_flag = G_define_flag();
    print_flag->key = 'p';
    print_flag->label =
	_("Print output to stdout, do not update attribute table");
    print_flag->description = _("First column is always area category");

    if (G_parser(argc, argv))
	exit(EXIT_FAILURE);

    point_type = Vect_option_to_types(point_type_opt);

    point_field = atoi(point_field_opt->answer);
    area_field = atoi(area_field_opt->answer);

    strcpy(fs, " ");
    if (print_flag->answer) {
	/* get field separator */
	if (fs_opt->answer) {
	    if (strcmp(fs_opt->answer, "space") == 0)
		*fs = ' ';
	    else if (strcmp(fs_opt->answer, "tab") == 0)
		*fs = '\t';
	    else if (strcmp(fs_opt->answer, "\\t") == 0)
		*fs = '\t';
	    else
		*fs = *fs_opt->answer;
	}
	else
	    *fs = '|';
    }

    /* check for stats */
    if (method_opt->answer) {
	if (!point_column_opt->answer) {
	    G_fatal_error("Method but no point column selected");
	}
	if (!print_flag->answer && !stats_column_opt->answer)
	    G_fatal_error("Name for stats column is missing");
    }

    if (point_column_opt->answer) {
	if (!method_opt->answer)
	    G_fatal_error("No method for statistics selected");
	if (!print_flag->answer && !stats_column_opt->answer)
	    G_fatal_error("Name for stats column is missing");
    }
    
    /* Open points vector */
    if ((mapset = G_find_vector2(point_opt->answer, "")) == NULL)
	G_fatal_error(_("Vector map <%s> not found"), point_opt->answer);

    Vect_set_open_level(2);
    Vect_open_old(&PIn, point_opt->answer, mapset);

    /* Open areas vector */
    if ((mapset = G_find_vector2(area_opt->answer, "")) == NULL)
	G_fatal_error(_("Vector map <%s> not found"), area_opt->answer);
    if (!print_flag->answer && strcmp(mapset, G_mapset()) != 0)
	G_fatal_error(_("Vector map <%s> is not in user mapset and cannot be updated"),
		      area_opt->answer);

    Vect_set_open_level(2);
    Vect_open_old(&AIn, area_opt->answer, mapset);

    method = -1;
    use_catno = 0;
    half = 0;
    if (method_opt->answer) {
	/* get the method */
	for (method = 0; (p = menu[method].name); method++)
	    if ((strcmp(p, method_opt->answer) == 0))
		break;
	if (!p) {
	    G_warning(_("<%s=%s> unknown %s"),
		      method_opt->key, method_opt->answer,
		      method_opt->answer);
	    G_usage();
	    exit(EXIT_FAILURE);
	}

	/* establish the statsvalue routine */
	statsvalue = menu[method].method;

	/* category number of lowest/highest value */
	if ((strcmp(menu[method].name, menu[5].name) == 0) ||
	    (strcmp(menu[method].name, menu[7].name) == 0))
	    use_catno = 1;

	G_debug(1, "method: %s, use cat value: %s", menu[method].name,
		(use_catno == 1 ? "yes" : "no"));
    }

    /* Open database driver */
    db_init_string(&stmt);
    Adriver = NULL;

    if (!print_flag->answer) {

	AFi = Vect_get_field(&AIn, area_field);
	if (AFi == NULL)
	    G_fatal_error(_("Database connection not defined for layer %d"),
			  area_field);

	Adriver = db_start_driver_open_database(AFi->driver, AFi->database);
	if (Adriver == NULL)
	    G_fatal_error(_("Unable to open database <%s> with driver <%s>"),
			  AFi->database, AFi->driver);

	if (!count_column_opt->answer)
	    G_fatal_error(_("ccolumn is required to upload point counts"));

	/* check if count column exists */
	G_debug(1, "check if count column exists");
	db_get_column(Adriver, AFi->table, count_column_opt->answer, &column);
	if (column) {
	    /* check count column type */
	    if (db_column_Ctype(Adriver, AFi->table, count_column_opt->answer)
		!= DB_C_TYPE_INT)
		G_fatal_error(_("ccolumn must be of type integer"));

	    db_free_column(column);
	    column = NULL;
	}
	else {
	    /* create count column */
	    /* db_add_column() exists but is not implemented,
	     * see lib/db/stubs/add_col.c */
	    sprintf(buf, "alter table %s add column %s integer",
	                    AFi->table, count_column_opt->answer);
	    db_set_string(&stmt, buf);
	    if (db_execute_immediate(Adriver, &stmt) != DB_OK)
		G_fatal_error(_("Unable to add column <%s>"),
			      count_column_opt->answer);
	}

	if (method_opt->answer) {
	    if (!stats_column_opt->answer)
		G_fatal_error(_("scolumn is required to upload point stats"));

	    /* check if stats column exists */
	    G_debug(1, "check if stats column exists");
	    db_get_column(Adriver, AFi->table, stats_column_opt->answer,
			  &column);
	    if (column) {
		/* check stats column type */
		if (db_column_Ctype
		    (Adriver, AFi->table,
		     stats_column_opt->answer) != DB_C_TYPE_DOUBLE)
		    G_fatal_error(_("scolumn must be of type double"));

		db_free_column(column);
		column = NULL;
	    }
	    else {
		/* create stats column */
		/* db_add_column() exists but is not implemented,
		 * see lib/db/stubs/add_col.c */
		sprintf(buf, "alter table %s add column %s double",
				AFi->table, stats_column_opt->answer);
		db_set_string(&stmt, buf);
		if (db_execute_immediate(Adriver, &stmt) != DB_OK)
		    G_fatal_error(_("Unable to add column <%s>"),
				  stats_column_opt->answer);
	    }
	}
    }
    else
	AFi = NULL;

    Pdriver = NULL;
    if (method_opt->answer) {

	G_verbose_message(_("collecting attributes from points vector..."));

	PFi = Vect_get_field(&PIn, point_field);
	if (PFi == NULL)
	    G_fatal_error(_("Database connection not defined for layer %d"),
			  point_field);

	Pdriver = db_start_driver_open_database(PFi->driver, PFi->database);
	if (Pdriver == NULL)
	    G_fatal_error(_("Unable to open database <%s> with driver <%s>"),
			  PFi->database, PFi->driver);

	/* check if point column exists */
	db_get_column(Pdriver, PFi->table, point_column_opt->answer, &column);
	if (column) {
	    db_free_column(column);
	    column = NULL;
	}
	else {
	    G_fatal_error(_("Column <%s> not found in table <%s>"),
			  point_column_opt->answer, PFi->table);
	}

	/* Check column type */
	ctype =
	    db_column_Ctype(Pdriver, PFi->table, point_column_opt->answer);

	if (ctype == DB_C_TYPE_INT)
	    half = menu[method].half;
	else if (ctype == DB_C_TYPE_DOUBLE)
	    half = 0;
	else
	    G_fatal_error(_("column for points vector must be numeric"));

	db_CatValArray_init(&cvarr);
	nrec = db_select_CatValArray(Pdriver, PFi->table, PFi->key,
				     point_column_opt->answer, NULL, &cvarr);
	G_debug(1, "selected values = %d", nrec);
	db_close_database_shutdown_driver(Pdriver);
    }

    Points = Vect_new_line_struct();
    ACats = Vect_new_cats_struct();
    PCats = Vect_new_cats_struct();
    List = Vect_new_boxlist(0);

    /* Allocate space ( may be more than needed (duplicate cats and elements without cats) ) */
    if ((nareas = Vect_get_num_areas(&AIn)) <= 0)
	G_fatal_error("No areas in area input vector");

    nacatsalloc = nareas;
    Area_cat = (AREA_CAT *) G_calloc(nacatsalloc, sizeof(AREA_CAT));

    /* Read all cats from 'area' */
    nacats = 0;
    for (area = 1; area <= nareas; area++) {

	Vect_get_area_cats(&AIn, area, ACats);

	if (ACats->n_cats <= 0)
	    continue;
	for (i = 0; i < ACats->n_cats; i++) {

	    if (ACats->field[i] == area_field) {
		Area_cat[nacats].area_cat = ACats->cat[i];
		Area_cat[nacats].count = 0;
		Area_cat[nacats].nvalues = 0;
		Area_cat[nacats].nalloc = 0;
		nacats++;
		if (nacats >= nacatsalloc) {
		    nacatsalloc += 100;
		    Area_cat =
			(AREA_CAT *) G_realloc(Area_cat,
					       nacatsalloc *
					       sizeof(AREA_CAT));
		}
	    }

	}
    }

    G_debug(1, "%d cats loaded from vector (including duplicates)", nacats);

    /* Sort by category */
    qsort((void *)Area_cat, nacats, sizeof(AREA_CAT), cmp_area);

    /* remove duplicate categories */
    for (i = 1; i < nacats; i++) {
	if (Area_cat[i].area_cat == Area_cat[i - 1].area_cat) {
	    for (j = i; j < nacats - 1; j++) {
		Area_cat[j].area_cat = Area_cat[j + 1].area_cat;
	    }
	    nacats--;
	}
    }

    G_debug(1, "%d cats loaded from vector (unique)", nacats);

    /* Go through all areas in area vector and find points in points vector
     * falling into the area */
    npvalcatsalloc = 10;
    npvalcats = 0;
    pvalcats =
	(struct pvalcat *)G_calloc(npvalcatsalloc, sizeof(struct pvalcat));

    G_message(_("Selecting points for each area..."));
    count = 0;
    for (area = 1; area <= nareas; area++) {
	dbCatVal *catval;

	G_debug(3, "area = %d", area);
	G_percent(area, nareas, 2);

	Vect_get_area_cats(&AIn, area, ACats);

	if (ACats->n_cats <= 0)
	    continue;

	/* select points by box */
	Vect_get_area_box(&AIn, area, &box);
	box.T = PORT_DOUBLE_MAX;
	box.B = -PORT_DOUBLE_MAX;

	Vect_select_lines_by_box(&PIn, &box, point_type, List);
	G_debug(4, "%d points selected by box", List->n_values);

	/* For each point in box check if it is in the area */
	for (i = 0; i < List->n_values; i++) {

	    pline = List->id[i];
	    G_debug(4, "%d: point %d", i, pline);

	    ptype = Vect_read_line(&PIn, Points, PCats, pline);
	    if (!(ptype & point_type))
		continue;

	    /* point in area */
	    if (Vect_point_in_area(Points->x[0], Points->y[0], &AIn, area, box)) {
		AREA_CAT *area_info, search_ai;

		int tmp_cat;

		/* stats on point column */
		if (method_opt->answer) {
		    npvalcats = 0;
		    tmp_cat = -1;
		    for (j = 0; j < PCats->n_cats; j++) {
			if (PCats->field[j] == point_field) {
			    if (tmp_cat >= 0)
				G_debug(3,
					"More cats found in point layer (point=%d)",
					pline);
			    tmp_cat = PCats->cat[j];

			    /* find cat in array */
			    db_CatValArray_get_value(&cvarr, tmp_cat,
						     &catval);

			    if (catval) {
				pvalcats[npvalcats].catno = tmp_cat;
				switch (cvarr.ctype) {
				case DB_C_TYPE_INT:
				    pvalcats[npvalcats].dval = catval->val.i;
				    npvalcats++;
				    break;

				case DB_C_TYPE_DOUBLE:
				    pvalcats[npvalcats].dval = catval->val.d;
				    npvalcats++;
				    break;
				}
				if (npvalcats >= npvalcatsalloc) {
				    npvalcatsalloc += 10;
				    pvalcats =
					(struct pvalcat *)G_realloc(pvalcats,
								    npvalcatsalloc
								    *
								    sizeof
								    (struct
								     pvalcat));
				}
			    }
			}
		    }
		}

		/* update count for all area cats of given field */
		search_ai.area_cat = -1;
		for (j = 0; j < ACats->n_cats; j++) {
		    if (ACats->field[j] == area_field) {
			if (search_ai.area_cat >= 0)
			    G_debug(3,
				    "More cats found in area layer (area=%d)",
				    area);
			search_ai.area_cat = ACats->cat[j];

			/* find cat in array */
			area_info =
			    (AREA_CAT *) bsearch((void *)&search_ai, Area_cat,
						 nacats, sizeof(AREA_CAT),
						 cmp_area);
			if (area_info->area_cat != search_ai.area_cat)
			    G_fatal_error(_("could not find area category %d"),
					  search_ai.area_cat);

			/* each point is counted once, also if it has
			 * more than one category or no category
			 * OK? */
			area_info->count++;

			if (method_opt->answer) {
			    /* ensure enough space */
			    if (area_info->nvalues + npvalcats >=
				area_info->nalloc) {
				if (area_info->nalloc == 0) {
				    area_info->nalloc = npvalcats + 10;
				    area_info->values =
					(double *)G_calloc(area_info->nalloc,
							   sizeof(double));
				    area_info->cats =
					(int *)G_calloc(area_info->nalloc,
							sizeof(int));
				}
				else
				    area_info->nalloc +=
					area_info->nvalues + npvalcats + 10;
				area_info->values =
				    (double *)G_realloc(area_info->values,
							area_info->nalloc *
							sizeof(double));
				area_info->cats =
				    (int *)G_realloc(area_info->cats,
						     area_info->nalloc *
						     sizeof(int));
			    }
			    for (k = 0; k < npvalcats; k++) {
				area_info->cats[area_info->nvalues] =
				    pvalcats[k].catno;
				area_info->values[area_info->nvalues] =
				    pvalcats[k].dval;
				area_info->nvalues++;
			    }
			}
		    }
		}
		count++;
	    }
	}			/* next point in box */
    }				/* next area */

    G_debug(1, "count = %d", count);

    /* release catval array */
    if (method_opt->answer)
	db_CatValArray_free(&cvarr);

    Vect_close(&PIn);

    /* Update table or print to stdout */
    if (print_flag->answer) {	/* print header */
	fprintf(stdout, "area_cat%scount", fs);
	if (method_opt->answer)
	    fprintf(stdout, "%s%s", fs, menu[method].name);
	fprintf(stdout, "\n");
    }
    else {
	G_message("Updating attributes for area vector...");
	update_err = update_ok = 0;
    }
    if (Adriver)
	db_begin_transaction(Adriver);

    for (i = 0; i < nacats; i++) {
	if (!print_flag->answer)
	    G_percent(i, nacats, 2);

	result = 0;

	if (Area_cat[i].count > 0 && method_opt->answer) {
	    /* get stats */
	    statsvalue(&result, Area_cat[i].values, Area_cat[i].nvalues,
			NULL);

	    if (half)
		result += 0.5;
	    else if (use_catno)
		result = Area_cat[i].cats[(int)result];
	}
	if (print_flag->answer) {
	    fprintf(stdout, "%d%s%d", Area_cat[i].area_cat, fs,
		    Area_cat[i].count);
	    if (method_opt->answer) {
		if (Area_cat[i].count > 0)
		    fprintf(stdout, "%s%.15g", fs, result);
		else
		    fprintf(stdout, "%snull", fs);
	    }
	    fprintf(stdout, "\n");
	}
	else {
	    sprintf(buf, "update %s set %s = %d", AFi->table,
		    count_column_opt->answer, Area_cat[i].count);
	    db_set_string(&stmt, buf);
	    if (method_opt->answer) {
		if (Area_cat[i].count > 0)
		    sprintf(buf, " , %s = %.15g", stats_column_opt->answer,
			    result);
		else
		    sprintf(buf, " , %s = null", stats_column_opt->answer);
		db_append_string(&stmt, buf);
	    }
	    sprintf(buf, " where %s = %d", AFi->key, Area_cat[i].area_cat);
	    db_append_string(&stmt, buf);
	    G_debug(2, "SQL: %s", db_get_string(&stmt));
	    if (db_execute_immediate(Adriver, &stmt) == DB_OK) {
		update_ok++;
	    }
	    else {
		update_err++;
	    }

	}
    }
    if (Adriver)
	db_commit_transaction(Adriver);

    if (!print_flag->answer) {
	G_percent(nacats, nacats, 2);
	db_close_database_shutdown_driver(Adriver);
	db_free_string(&stmt);
	G_message(_("%d records updated"), update_ok);
	if (update_err > 0)
	    G_message(_("%d update errors"), update_err);

	Vect_set_db_updated(&AIn);
    }

    Vect_close(&AIn);

    G_done_msg(" ");

    exit(EXIT_SUCCESS);
}
Exemplo n.º 4
0
void select_from_database(void)
{
    int nrec, ctype, nlines, line, nareas, area;
    struct line_pnts *Points;

    Fi = Vect_get_field(&Map, ofield);
    if (Fi == NULL) {
	G_fatal_error(_(" Database connection not defined for layer <%s>"), field_opt->answer);
    }

    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_set_error_handler_driver(Driver);

    /* check if column exists */
    ctype = db_column_Ctype(Driver, Fi->table, col_opt->answer);
    if (ctype == -1)
        G_fatal_error(_("Column <%s> not found in table <%s>"),
                      col_opt->answer, Fi->table);
    if (ctype != DB_C_TYPE_INT && ctype != DB_C_TYPE_DOUBLE)
	G_fatal_error(_("Only numeric column type is supported"));
    
    /* Note do not check if the column exists in the table because it may be an expression */
    db_CatValArray_init(&Cvarr);
    nrec = db_select_CatValArray(Driver, Fi->table, Fi->key, col_opt->answer,
                                 where_opt->answer, &Cvarr);
    G_debug(2, "db_select_CatValArray() nrec = %d", nrec);
    if (nrec < 0)
	G_fatal_error(_("Unable to select data from table"));

    db_close_database_shutdown_driver(Driver);

    Points = Vect_new_line_struct();

    /* Lines */
    nlines = 0;
    if ((otype & GV_POINTS) || (otype & GV_LINES))
	nlines = Vect_get_num_lines(&Map);

    G_debug(1, "select_from_database: %d points", nlines);
    for (line = 1; line <= nlines; line++) {
	int i, type;

	G_debug(3, "line = %d", line);

	G_percent(line, nlines, 2);
	type = Vect_read_line(&Map, Points, Cats, line);
	if (!(type & otype))
	    continue;

	for (i = 0; i < Cats->n_cats; i++) {
	    if (Cats->field[i] == ofield) {
		double val = 0.0;
		dbCatVal *catval;

		G_debug(3, "cat = %d", Cats->cat[i]);

		if (db_CatValArray_get_value(&Cvarr, Cats->cat[i], &catval) !=
		    DB_OK) {
		    G_debug(3, "No record for cat = %d", Cats->cat[i]);
		    nmissing++;
		    continue;
		}

		if (catval->isNull) {
		    G_debug(3, "NULL value for cat = %d", Cats->cat[i]);
		    nnull++;
		    continue;
		}

		if (ctype == DB_C_TYPE_INT) {
		    val = catval->val.i;
		}
		else if (ctype == DB_C_TYPE_DOUBLE) {
		    val = catval->val.d;
		}

		count++;

		if (first) {
		    max = val;
		    min = val;
		    first = 0;
		}
		else {
		    if (val > max)
			max = val;
		    if (val < min)
			min = val;
		}

		if (compatible) {
		    if (type & GV_POINTS) {
			sum += val;
			sumsq += val * val;
			sumcb += val * val * val;
			sumqt += val * val * val * val;
			sum_abs += fabs(val);
		    }
		    else if (type & GV_LINES) {	/* GV_LINES */
			double l = 1.;

			if (weight_flag->answer)
			    l = Vect_line_length(Points);

			sum += l * val;
			sumsq += l * val * val;
			sumcb += l * val * val * val;
			sumqt += l * val * val * val * val;
			sum_abs += l * fabs(val);
			total_size += l;
		    }
		}
		G_debug(3, "sum = %f total_size = %f", sum, total_size);
	    }
	}
    }

    if (otype & GV_AREA) {
	nareas = Vect_get_num_areas(&Map);
	for (area = 1; area <= nareas; area++) {
	    int i, centr;

	    G_debug(3, "area = %d", area);

	    centr = Vect_get_area_centroid(&Map, area);
	    if (centr < 1)
		continue;

	    G_debug(3, "centr = %d", centr);
	    Vect_read_line(&Map, NULL, Cats, centr);

	    for (i = 0; i < Cats->n_cats; i++) {
		if (Cats->field[i] == ofield) {
		    double val = 0.0;
		    dbCatVal *catval;

		    G_debug(3, "cat = %d", Cats->cat[i]);

		    if (db_CatValArray_get_value
			(&Cvarr, Cats->cat[i], &catval) != DB_OK) {
			G_debug(3, "No record for cat = %d", Cats->cat[i]);
			nmissing++;
			continue;
		    }

		    if (catval->isNull) {
			G_debug(3, "NULL value for cat = %d", Cats->cat[i]);
			nnull++;
			continue;
		    }

		    if (ctype == DB_C_TYPE_INT) {
			val = catval->val.i;
		    }
		    else if (ctype == DB_C_TYPE_DOUBLE) {
			val = catval->val.d;
		    }

		    count++;

		    if (first) {
			max = val;
			min = val;
			first = 0;
		    }
		    else {
			if (val > max)
			    max = val;
			if (val < min)
			    min = val;
		    }

		    if (compatible) {
			double a = 1.;

			if (weight_flag->answer)
			    a = Vect_get_area_area(&Map, area);

			sum += a * val;
			sumsq += a * val * val;
			sumcb += a * val * val * val;
			sumqt += a * val * val * val * val;
			sum_abs += a * fabs(val);
			total_size += a;
		    }
		    G_debug(4, "sum = %f total_size = %f", sum, total_size);
		}
	    }
	}
    }

    G_debug(2, "sum = %f total_size = %f", sum, total_size);
}
Exemplo n.º 5
0
int main(int argc, char *argv[])
{
    struct GModule *module;
    struct Option *map_opt, *type_opt,
	*percentile;

    module = G_define_module();
    G_add_keyword(_("vector"));
    G_add_keyword(_("statistics"));
    G_add_keyword(_("univariate statistics"));
    G_add_keyword(_("attribute table"));
    G_add_keyword(_("geometry"));
    module->label =
	_("Calculates univariate statistics of vector map features.");
    module->description = _("Variance and standard "
			    "deviation is calculated only for points if specified.");

    map_opt = G_define_standard_option(G_OPT_V_MAP);

    field_opt = G_define_standard_option(G_OPT_V_FIELD);

    type_opt = G_define_standard_option(G_OPT_V_TYPE);
    type_opt->options = "point,line,boundary,centroid,area";
    type_opt->answer = "point,line,area";

    col_opt = G_define_standard_option(G_OPT_DB_COLUMN);
    col_opt->required = NO;

    where_opt = G_define_standard_option(G_OPT_DB_WHERE);

    percentile = G_define_option();
    percentile->key = "percentile";
    percentile->type = TYPE_INTEGER;
    percentile->required = NO;
    percentile->options = "0-100";
    percentile->answer = "90";
    percentile->description =
	_("Percentile to calculate (requires extended statistics flag)");

    shell_flag = G_define_flag();
    shell_flag->key = 'g';
    shell_flag->description = _("Print the stats in shell script style");

    ext_flag = G_define_flag();
    ext_flag->key = 'e';
    ext_flag->description = _("Calculate extended statistics");

    weight_flag = G_define_flag();
    weight_flag->key = 'w';
    weight_flag->description = _("Weigh by line length or area size");

    geometry = G_define_flag();
    geometry->key = 'd';
    geometry->description = _("Calculate geometric distances instead of attribute statistics");

    G_gisinit(argv[0]);

    if (G_parser(argc, argv))
	exit(EXIT_FAILURE);

    /* Only require col_opt answer if -g flag is not set */
    if (!col_opt->answer && !geometry->answer) {
	G_fatal_error(_("Required parameter <%s> not set:\n\t(%s)"), col_opt->key, col_opt->description);
    }

    otype = Vect_option_to_types(type_opt);
    perc = atoi(percentile->answer);

    Cats = Vect_new_cats_struct();

    /* open input vector */
    Vect_set_open_level(2);
    if (Vect_open_old2(&Map, map_opt->answer, "", field_opt->answer) < 0)
	G_fatal_error(_("Unable to open vector map <%s>"), map_opt->answer);

    ofield = Vect_get_field_number(&Map, field_opt->answer);
    
    if ((otype & GV_POINT) && Vect_get_num_primitives(&Map, GV_POINT) == 0) {
	otype &= ~(GV_POINT);
	if (otype & GV_POINT)
	    G_fatal_error("Bye");
    }
    if ((otype & GV_CENTROID) && Vect_get_num_primitives(&Map, GV_CENTROID) == 0) {
	otype &= ~(GV_CENTROID);
    }
    if ((otype & GV_LINE) && Vect_get_num_primitives(&Map, GV_LINE) == 0) {
	otype &= ~(GV_LINE);
    }
    if ((otype & GV_BOUNDARY) && Vect_get_num_primitives(&Map, GV_BOUNDARY) == 0) {
	otype &= ~(GV_BOUNDARY);
    }
    if ((otype & GV_AREA) && Vect_get_num_areas(&Map) == 0) {
	otype &= ~(GV_AREA);
    }

    /* Check if types are compatible */
    if ((otype & GV_POINTS) && ((otype & GV_LINES) || (otype & GV_AREA)))
	compatible = 0;
    if ((otype & GV_LINES) && (otype & GV_AREA))
	compatible = 0;
    if (!compatible && geometry->answer)
	compatible = 1; /* distances is compatible with GV_POINTS and GV_LINES */

    if (!compatible && !weight_flag->answer)
	compatible = 1; /* attributes are always compatible without weight */

    if (geometry->answer && (otype & GV_AREA))
	G_fatal_error(_("Geometry distances are not supported for areas. Use '%s' instead."), "v.distance");

    if (!compatible) {
	G_warning(_("Incompatible vector type(s) specified, only number of features, minimum, maximum and range "
		   "can be calculated"));
    }

    if (ext_flag->answer && (!(otype & GV_POINTS) || geometry->answer)) {
	G_warning(_("Extended statistics is currently supported only for points/centroids"));
    }

    if (geometry->answer)
	select_from_geometry();
    else
	select_from_database();
    summary();

    Vect_close(&Map);

    exit(EXIT_SUCCESS);
}
Exemplo n.º 6
0
/*!
   \brief Set values in 'varray' to 'value'

   If category of object of given type is in 'clist' (category list).
   'type' may be either: GV_AREA or: GV_POINT | GV_LINE | GV_BOUNDARY |
   GV_CENTROID

   Array is not reset to zero before, but old values (if any > 0) are overwritten.
   Array must be initialised by Vect_new_varray(size) call.

   \param Map vector map
   \param field layer number
   \param clist list of categories
   \param type feature type
   \param value value to set up
   \param[in,out] varray varray structure to modify

   \return number of items set
   \return -1 on error
 */
int
Vect_set_varray_from_cat_list(struct Map_info *Map, int field,
			      struct cat_list *clist, int type, int value,
			      VARRAY * varray)
{
    int i, n, centr, cat;
    int ni = 0;			/* number of items set */
    int ltype;			/* line type */
    struct line_cats *Cats;

    G_debug(4, "Vect_set_varray_from_cat_list(): field = %d", field);

    /* Check type */
    if ((type & GV_AREA) && (type & (GV_POINTS | GV_LINES))) {
	G_warning(_("Mixed area and other type requested for vector array"));
	return 0;
    }

    Cats = Vect_new_cats_struct();

    if (type & GV_AREA) {	/* Areas */
	n = Vect_get_num_areas(Map);

	if (n > varray->size) {	/* not enough space */
	    G_warning(_("Not enough space in vector array"));
	    return 0;
	}

	for (i = 1; i <= n; i++) {
	    centr = Vect_get_area_centroid(Map, i);
	    if (centr <= 0)
		continue;	/* No centroid */

	    Vect_read_line(Map, NULL, Cats, centr);
	    if (!Vect_cat_get(Cats, field, &cat))
		continue;	/* No such field */

	    if (Vect_cat_in_cat_list(cat, clist)) {	/* cat is in list */
		varray->c[i] = value;
		ni++;
	    }
	}
    }
    else {			/* Lines */
	n = Vect_get_num_lines(Map);

	if (n > varray->size) {	/* not enough space */
	    G_warning(_("Not enough space in vector array"));
	    return 0;
	}

	for (i = 1; i <= n; i++) {
	    ltype = Vect_read_line(Map, NULL, Cats, i);

	    if (!(ltype & type))
		continue;	/* is not specified type */

	    if (!Vect_cat_get(Cats, field, &cat))
		continue;	/* No such field */

	    if (Vect_cat_in_cat_list(cat, clist)) {	/* cat is in list */
		varray->c[i] = value;
		ni++;
	    }
	}

    }

    Vect_destroy_cats_struct(Cats);

    return ni;
}
Exemplo n.º 7
0
/*!
   \brief Set values in 'varray' to 'value'.

   if category of object of given type is in categories selected from
   DB based on where statement (given without where).  'type' may be
   either: GV_AREA or: GV_POINT | GV_LINE | GV_BOUNDARY | GV_CENTROID

   Array is not reset to zero before, but old values (if any > 0) are
   overwritten. Array must be initialised by Vect_new_varray(size) call.

   \param Map vector map
   \param field layer number
   \param where where statement
   \param type feature type
   \param value value to set up
   \param[in,out] varray varray structure to modify

   \return number of items set
   \return -1 on error
 */
int
Vect_set_varray_from_db(struct Map_info *Map, int field, const char *where,
			int type, int value, VARRAY * varray)
{
    int i, n, c, centr, cat, *cats;
    int ncats;
    int ni = 0;			/* number of items set */
    int ltype;			/* line type */
    struct line_cats *Cats;
    struct field_info *Fi;
    dbDriver *driver;

    G_debug(4, "Vect_set_varray_from_db(): field = %d where = '%s'", field,
	    where);

    /* Note: use category index once available */

    /* Check type */
    if ((type & GV_AREA) && (type & (GV_POINTS | GV_LINES))) {
	G_warning(_("Mixed area and other type requested for vector array"));
	return 0;
    }

    Cats = Vect_new_cats_struct();

    /* Select categories from DB to array */
    Fi = Vect_get_field(Map, field);
    if (Fi == NULL) {
	G_warning(_("Database connection not defined for layer %d"), field);
	return -1;
    }

    driver = db_start_driver_open_database(Fi->driver, Fi->database);
    if (driver == NULL) {
	G_warning(_("Unable to open database <%s> by driver <%s>"),
		  Fi->database, Fi->driver);
	return -1;
    }

    ncats = db_select_int(driver, Fi->table, Fi->key, where, &cats);

    db_close_database_shutdown_driver(driver);

    if (ncats == -1) {
	G_warning(_("Unable to select record from table <%s> (key %s, where %s)"),
		  Fi->table, Fi->key, where);
	return -1;
    }

    if (type & GV_AREA) {	/* Areas */
	n = Vect_get_num_areas(Map);

        /* IMHO varray should be allocated only when it's required AND only as large as required
        as WHERE will create a small subset of all vector features and thus on large datasets
        it's waste of memory to allocate it for all features. */
	if (n > varray->size) {	/* not enough space */
	    G_warning(_("Not enough space in vector array"));
	    return 0;
	}

	for (i = 1; i <= n; i++) {
	    centr = Vect_get_area_centroid(Map, i);
	    if (centr <= 0)
		continue;	/* No centroid */

	    Vect_read_line(Map, NULL, Cats, centr);
	    /*if ( !Vect_cat_get(Cats, field, &cat) ) continue; No such field */
	    for (c = 0; c < Cats->n_cats; c++) {
		if (Cats->field[c] == field &&
		    in_array(cats, ncats, Cats->cat[c])) {
		    cat = Cats->cat[c];
		    varray->c[i] = value;
		    ni++;
		    break;
		}
	    }

	    /*
	       if ( in_array ( cats, ncats, cat ) ) {
	       varray->c[i] = value;
	       ni++;
	       }
	     */
	}
    }
    else {			/* Lines */
	n = Vect_get_num_lines(Map);

	if (n > varray->size) {	/* not enough space */
	    G_warning(_("Not enough space in vector array"));
	    return 0;
	}

	for (i = 1; i <= n; i++) {
	    ltype = Vect_read_line(Map, NULL, Cats, i);

	    if (!(ltype & type))
		continue;	/* is not specified type */

	    /* if ( !Vect_cat_get(Cats, field, &cat) ) continue;  No such field */
	    for (c = 0; c < Cats->n_cats; c++) {
		if (Cats->field[c] == field &&
		    in_array(cats, ncats, Cats->cat[c])) {
		    cat = Cats->cat[c];
		    varray->c[i] = value;
		    ni++;
		    break;
		}
	    }
	    /*
	       if ( in_array ( cats, ncats, cat ) ) {
	       varray->c[i] = value;
	       ni++;
	       }
	     */
	}

    }

    G_free(cats);
    Vect_destroy_cats_struct(Cats);

    return ni;
}
Exemplo n.º 8
0
Arquivo: area.c Projeto: caomw/grass
int display_area(struct Map_info *Map, struct cat_list *Clist, const struct Cell_head *window,
		 const struct color_rgb *bcolor, const struct color_rgb *fcolor, int chcat,
		 int id_flag, int cats_color_flag, 
		 int default_width, double width_scale,
		 struct Colors *zcolors,
		 dbCatValArray *cvarr_rgb, struct Colors *colors,
		 dbCatValArray *cvarr_width, int nrec_width)
{
    int num, area, isle, n_isles, n_points;
    double xl, yl;
    struct line_pnts *Points, * APoints, **IPoints;
    struct line_cats *Cats;
    int n_ipoints_alloc;
    int cat, centroid;
    int red, grn, blu;

    int i, custom_rgb, found;
    int width;
    struct bound_box box;
    
    if (Vect_level(Map) < 2) {
	G_warning(_("Unable to display areas, topology not available. "
		    "Please try to rebuild topology using "
		    "v.build or v.build.all."));
	return 1;
    }

    G_debug(1, "display areas:");
    
    centroid = 0;
    Points = Vect_new_line_struct();
    APoints = Vect_new_line_struct();
    n_ipoints_alloc = 10;
    IPoints = (struct line_pnts **)G_malloc(n_ipoints_alloc * sizeof(struct line_pnts *));
    for (i = 0; i < n_ipoints_alloc; i++) {
	IPoints[i] = Vect_new_line_struct();
    }
    Cats = Vect_new_cats_struct();
    
    num = Vect_get_num_areas(Map);
    G_debug(2, "\tn_areas = %d", num);

    for (area = 1; area <= num; area++) {
	G_debug(3, "\tarea = %d", area);

	if (!Vect_area_alive(Map, area))
	    continue;

	centroid = Vect_get_area_centroid(Map, area);
	if (!centroid) {
	    continue;
	}

	/* Check box */
	Vect_get_area_box(Map, area, &box);
	if (box.N < window->south || box.S > window->north ||
	    box.E < window->west || box.W > window->east) {
	    if (window->proj != PROJECTION_LL)
		continue;
	    else { /* out of bounds for -180 to 180, try 0 to 360 as well */
		if (box.N < window->south || box.S > window->north)
		    continue;
		if (box.E + 360 < window->west || box.W + 360 > window->east)
		    continue;
	    }
	}

	custom_rgb = FALSE;
		
	found = FALSE;
	if (chcat) {		
	    if (id_flag) {
		if (!(Vect_cat_in_cat_list(area, Clist)))
		    continue;
	    }
	    else {
		G_debug(3, "centroid = %d", centroid);
		if (centroid < 1)
		    continue;
		Vect_read_line(Map, Points, Cats, centroid);

		for (i = 0; i < Cats->n_cats; i++) {
		    G_debug(3, "  centroid = %d, field = %d, cat = %d",
			    centroid, Cats->field[i], Cats->cat[i]);

		    if (Cats->field[i] == Clist->field &&
			Vect_cat_in_cat_list(Cats->cat[i], Clist)) {
			found = TRUE;
			break;
		    }
		}
		
		if (!found)
		    continue;
	    }
	}
	else if (Clist->field > 0) {
	    found = FALSE;
	    G_debug(3, "\tcentroid = %d", centroid);
	    if (centroid < 1)
		continue;
	    Vect_read_line(Map, NULL, Cats, centroid);

	    for (i = 0; i < Cats->n_cats; i++) {
		G_debug(3, "\tcentroid = %d, field = %d, cat = %d", centroid,
			Cats->field[i], Cats->cat[i]);
		if (Cats->field[i] == Clist->field) {
		    found = TRUE;
		    break;
		}
	    }
	    
	    /* lines with no category will be displayed */
	    if (Cats->n_cats > 0 && !found)
		continue;
	}

	/* fill */
	Vect_get_area_points(Map, area, APoints);
	G_debug(3, "\tn_points = %d", APoints->n_points);
	if (APoints->n_points < 3) {
	    G_warning(_("Invalid area %d skipped (not enough points)"), area);
	    continue;
	}
	Vect_reset_line(Points);
	Vect_append_points(Points, APoints, GV_FORWARD);

	n_points = Points->n_points;
	xl = Points->x[n_points - 1];
	yl = Points->y[n_points - 1];
	n_isles = Vect_get_area_num_isles(Map, area);
	if (n_isles >= n_ipoints_alloc) {
	    IPoints = (struct line_pnts **)G_realloc(IPoints, (n_isles + 10) * sizeof(struct line_pnts *));
	    for (i = n_ipoints_alloc; i < n_isles + 10; i++) {
		IPoints[i] = Vect_new_line_struct();
	    }
	    n_ipoints_alloc = n_isles + 10;
	}
	for (i = 0; i < n_isles; i++) {
	    isle = Vect_get_area_isle(Map, area, i);
	    Vect_get_isle_points(Map, isle, IPoints[i]);
	    Vect_append_points(Points, IPoints[i], GV_FORWARD);
	    Vect_append_point(Points, xl, yl, 0.0);	/* ??? */
	}

	cat = Vect_get_area_cat(Map, area,
				(Clist->field > 0 ? Clist->field :
				 (Cats->n_cats > 0 ? Cats->field[0] : 1)));

	if (!centroid && cat == -1) {
	    continue;
	}

	/* z height colors */
	if (zcolors) {
	    if (Rast_get_d_color(&Points->z[0], &red, &grn, &blu, zcolors) == 1)
		custom_rgb = TRUE;
	    else
		custom_rgb = FALSE;
	}

        /* custom colors */
	if (colors || cvarr_rgb) {
	    custom_rgb = get_table_color(cat, area, colors, cvarr_rgb,
					 &red, &grn, &blu);
	}
	
	/* random colors */
	if (cats_color_flag) {
	    custom_rgb = get_cat_color(area, Cats, Clist,
				       &red, &grn, &blu);
	}
	
	/* line width */
	if (nrec_width) {
	    width = (int) get_property(cat, area, cvarr_width,
				       (double) width_scale,
				       (double) default_width);
	    
	    D_line_width(width);
	}
	
	if (fcolor || zcolors) {
	    if (!cvarr_rgb && !cats_color_flag && !zcolors && !colors) {
		D_RGB_color(fcolor->r, fcolor->g, fcolor->b);
		D_polygon_abs(Points->x, Points->y, Points->n_points);
	    }
	    else {
		if (custom_rgb) {
		    D_RGB_color((unsigned char)red, (unsigned char)grn,
				(unsigned char)blu);
		}
		else {
		    D_RGB_color(fcolor->r, fcolor->g, fcolor->b);
		}
		if (cat >= 0) {
		    D_polygon_abs(Points->x, Points->y, Points->n_points);
		}
	    }
	}

	/* boundary */
	if (bcolor) {
	    if (custom_rgb) {
		D_RGB_color((unsigned char)red, (unsigned char)grn,
			    (unsigned char)blu);
	    }
	    else {
		D_RGB_color(bcolor->r, bcolor->g, bcolor->b);
	    }
	    /* use different user defined render methods */
	    D_polyline_abs(APoints->x, APoints->y, APoints->n_points);
	    for (i = 0; i < n_isles; i++) {
		/* use different user defined render methods */
		D_polyline_abs(IPoints[i]->x, IPoints[i]->y, IPoints[i]->n_points);
	    }
	}
    }

    if ((colors || cvarr_rgb) && get_num_color_rules_skipped() > 0)
        G_warning(_n("%d invalid color rule for areas skipped", 
                "%d invalid color rules for areas skipped", 
                get_num_color_rules_skipped()), 
                get_num_color_rules_skipped());

    Vect_destroy_line_struct(Points);
    Vect_destroy_line_struct(APoints);
    for (i = 0; i < n_ipoints_alloc; i++) {
	Vect_destroy_line_struct(IPoints[i]);
    }
    G_free(IPoints);
    Vect_destroy_cats_struct(Cats);

    return 0;
}
Exemplo n.º 9
0
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 */
		(*n_nocat)++;
            }
            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;
}
Exemplo n.º 10
0
int vect_to_rast(const char *vector_map, const char *raster_map, const char *field_name,
		 const char *column, int cache_mb, int use, double value,
		 int value_type, const char *rgbcolumn, const char *labelcolumn,
		 int ftype, char *where, char *cats, int dense)
{
    struct Map_info Map;
    struct line_pnts *Points;
    int i, field;
    struct cat_list *cat_list = NULL;
    int fd;			/* for raster map */
    int nareas, nlines;		/* number of converted features */
    int nareas_all, nplines_all;	/* number of all areas, points/lines */
    int stat;
    int format;
    int pass, npasses;

    /* Attributes */
    int nrec;
    int ctype = 0;
    struct field_info *Fi;
    dbDriver *Driver;
    dbCatValArray cvarr;
    int is_fp = 0;

    nareas = 0;

    G_verbose_message(_("Loading data..."));
    Vect_set_open_level(2);
    if (Vect_open_old2(&Map, vector_map, "", field_name) < 0)
	G_fatal_error(_("Unable to open vector map <%s>"), vector_map);

    field = Vect_get_field_number(&Map, field_name);

    if (field > 0)
	cat_list = Vect_cats_set_constraint(&Map, field, where, cats);


    if ((use == USE_Z) && !(Vect_is_3d(&Map)))
	G_fatal_error(_("Vector map <%s> is not 3D"),
		      Vect_get_full_name(&Map));

    switch (use) {
    case USE_ATTR:
	db_CatValArray_init(&cvarr);
	if (!(Fi = Vect_get_field(&Map, field)))
	    G_fatal_error(_("Database connection not defined for layer <%s>"),
			  field_name);

	if ((Driver =
	     db_start_driver_open_database(Fi->driver, Fi->database)) == NULL)
	    G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
			  Fi->database, Fi->driver);
        db_set_error_handler_driver(Driver);

	/* Note do not check if the column exists in the table because it may be expression */

	if ((nrec =
	     db_select_CatValArray(Driver, Fi->table, Fi->key, column, NULL,
				   &cvarr)) == -1)
	    G_fatal_error(_("Column <%s> not found"), column);
	G_debug(3, "nrec = %d", nrec);

	ctype = cvarr.ctype;
	if (ctype != DB_C_TYPE_INT && ctype != DB_C_TYPE_DOUBLE)
	    G_fatal_error(_("Column type (%s) not supported (did you mean 'labelcolumn'?)"),
			  db_sqltype_name(ctype));

	if (nrec < 0)
	    G_fatal_error(_("No records selected from table <%s>"),
			  Fi->table);

	G_debug(1, "%d records selected from table", nrec);

	db_close_database_shutdown_driver(Driver);

	for (i = 0; i < cvarr.n_values; i++) {
	    if (ctype == DB_C_TYPE_INT) {
		G_debug(3, "cat = %d val = %d", cvarr.value[i].cat,
			cvarr.value[i].val.i);
	    }
	    else if (ctype == DB_C_TYPE_DOUBLE) {
		G_debug(3, "cat = %d val = %f", cvarr.value[i].cat,
			cvarr.value[i].val.d);
	    }
	}
	
	switch (ctype) {
	case DB_C_TYPE_INT:
	    format = CELL_TYPE;
	    break;
	case DB_C_TYPE_DOUBLE:
	    format = DCELL_TYPE;
	    break;
	default:
	    G_fatal_error(_("Unable to use column <%s>"), column);
	    break;
	}
	break;
    case USE_CAT:
	format = CELL_TYPE;
	break;
    case USE_VAL:
	format = value_type;
	break;
    case USE_Z:
	format = DCELL_TYPE;
	is_fp = 1;
	break;
    case USE_D:
	format = DCELL_TYPE;
	break;
    default:
	G_fatal_error(_("Unknown use type: %d"), use);
    }

    fd = Rast_open_new(raster_map, format);

    Points = Vect_new_line_struct();

    if (use != USE_Z && use != USE_D && (ftype & GV_AREA)) {
	if ((nareas = sort_areas(&Map, Points, field, cat_list)) == 0)
	    G_warning(_("No areas selected from vector map <%s>"),
			  vector_map);

	G_debug(1, "%d areas sorted", nareas);
    }
    if (nareas > 0 && dense) {
	G_warning(_("Area conversion and line densification are mutually exclusive, disabling line densification."));
	dense = 0;
    }

    nlines = Vect_get_num_primitives(&Map, ftype);
    nplines_all = nlines;
    npasses = begin_rasterization(cache_mb, format, dense);
    pass = 0;

    nareas_all = Vect_get_num_areas(&Map);

    do {
	pass++;

	if (npasses > 1)
	    G_message(_("Pass %d of %d:"), pass, npasses);

	stat = 0;

	if ((use != USE_Z && use != USE_D) && nareas) {
	    if (do_areas
		(&Map, Points, &cvarr, ctype, use, value,
		 value_type) < 0) {
		G_warning(_("Problem processing areas from vector map <%s>, continuing..."),
			  vector_map);
		stat = -1;
		break;
	    }
	}

	if (nlines) {
	    if ((nlines =
		 do_lines(&Map, Points, &cvarr, ctype, field, cat_list, 
		          use, value, value_type, ftype,
			  &nplines_all, dense)) < 0) {
		G_warning(_("Problem processing lines from vector map <%s>, continuing..."),
			  vector_map);
		stat = -1;
		break;
	    }
	}

	G_important_message(_("Writing raster map..."));

	stat = output_raster(fd);
    } while (stat == 0);

    G_suppress_warnings(0);
    /* stat: 0 == repeat; 1 == done; -1 == error; */

    Vect_destroy_line_struct(Points);

    if (stat < 0) {
	Rast_unopen(fd);

	return 1;
    }

    Vect_close(&Map);

    G_verbose_message(_("Creating support files for raster map..."));
    Rast_close(fd);
    update_hist(raster_map, vector_map, Map.head.orig_scale);

    /* colors */
    if (rgbcolumn) {
	if (use != USE_ATTR && use != USE_CAT) {
	    G_warning(_("Color can be updated from database only if use=attr"));
	    update_colors(raster_map);
	}
	else {
	  update_dbcolors(raster_map, vector_map, field, rgbcolumn, is_fp,
			  column);
	}
    }
    else if (use == USE_D)
	update_fcolors(raster_map);
    else
	update_colors(raster_map);

    update_cats(raster_map);

    /* labels */
    update_labels(raster_map, vector_map, field, labelcolumn, use, value,
		  column);

#if 0
    /* maximum possible numer of areas: number of centroids
     * actual number of areas, currently unknown:
     * number of areas with centroid that are within cat constraint
     * and overlap with current region */
    if (nareas_all > 0)
	G_message(_("Converted areas: %d of %d"), nareas,
	          Vect_get_num_primitives(&Map, GV_CENTROID));
    /* maximum possible numer of lines: number of GV_LINE + GV_POINT
     * actual number of lines, currently unknown:
     * number of lines are within cat constraint
     * and overlap with current region */
    if (nlines > 0 && nplines_all > 0)
	G_message(_("Converted points/lines: %d of %d"), nlines, nplines_all);
#endif

    return 0;
}
Exemplo n.º 11
0
int main(int argc, char *argv[])
{
    int i, j, k;
    int print_as_matrix;	/* only for all */
    int all;			/* calculate from each to each within the threshold */
    struct GModule *module;
    struct Option *from_opt, *to_opt, *from_type_opt, *to_type_opt,
	*from_field_opt, *to_field_opt;
    struct Option *out_opt, *max_opt, *min_opt, *table_opt;
    struct Option *upload_opt, *column_opt, *to_column_opt;
    struct Flag *print_flag, *all_flag;
    struct Map_info From, To, Out, *Outp;
    int from_type, to_type, from_field, to_field;
    double max, min;
    double *max_step;
    int n_max_steps, curr_step;
    struct line_pnts *FPoints, *TPoints;
    struct line_cats *FCats, *TCats;
    NEAR *Near, *near;
    int anear;			/* allocated space, used only for all */
    UPLOAD *Upload;		/* zero terminated */
    int ftype, fcat, tcat, count;
    int nfrom, nto, nfcats, fline, tline, tseg, tarea, area, isle, nisles;
    double tx, ty, tz, dist, talong, tmp_tx, tmp_ty, tmp_tz, tmp_dist,
	tmp_talong;
    struct field_info *Fi, *toFi;
    dbString stmt, dbstr;
    dbDriver *driver, *to_driver;
    int *catexist, ncatexist, *cex;
    char buf1[2000], buf2[2000];
    int update_ok, update_err, update_exist, update_notexist, update_dupl,
	update_notfound;
    struct boxlist *List;
    struct bound_box box;
    dbCatValArray cvarr;
    dbColumn *column;

    all = 0;
    print_as_matrix = 0;
    column = NULL;

    G_gisinit(argv[0]);

    module = G_define_module();
    G_add_keyword(_("vector"));
    G_add_keyword(_("database"));
    G_add_keyword(_("attribute table"));
    module->description =
	_("Finds the nearest element in vector map 'to' for elements in vector map 'from'.");

    from_opt = G_define_standard_option(G_OPT_V_INPUT);
    from_opt->key = "from";
    from_opt->description = _("Name of existing vector map (from)");
    from_opt->guisection = _("From");

    from_field_opt = G_define_standard_option(G_OPT_V_FIELD);
    from_field_opt->key = "from_layer";
    from_field_opt->label = _("Layer number or name (from)");
    from_field_opt->guisection = _("From");

    from_type_opt = G_define_standard_option(G_OPT_V_TYPE);
    from_type_opt->key = "from_type";
    from_type_opt->options = "point,centroid";
    from_type_opt->answer = "point";
    from_type_opt->label = _("Feature type (from)");
    from_type_opt->guisection = _("From");

    to_opt = G_define_standard_option(G_OPT_V_INPUT);
    to_opt->key = "to";
    to_opt->description = _("Name of existing vector map (to)");
    to_opt->guisection = _("To");

    to_field_opt = G_define_standard_option(G_OPT_V_FIELD);
    to_field_opt->key = "to_layer";
    to_field_opt->label = _("Layer number or name (to)");
    to_field_opt->guisection = _("To");

    to_type_opt = G_define_standard_option(G_OPT_V_TYPE);
    to_type_opt->key = "to_type";
    to_type_opt->options = "point,line,boundary,centroid,area";
    to_type_opt->answer = "point,line,area";
    to_type_opt->label = _("Feature type (to)");
    to_type_opt->guisection = _("To");

    out_opt = G_define_standard_option(G_OPT_V_OUTPUT);
    out_opt->key = "output";
    out_opt->required = NO;
    out_opt->description = _("Name for output vector map containing lines "
			     "connecting nearest elements");

    max_opt = G_define_option();
    max_opt->key = "dmax";
    max_opt->type = TYPE_DOUBLE;
    max_opt->required = NO;
    max_opt->answer = "-1";
    max_opt->description = _("Maximum distance or -1 for no limit");

    min_opt = G_define_option();
    min_opt->key = "dmin";
    min_opt->type = TYPE_DOUBLE;
    min_opt->required = NO;
    min_opt->answer = "-1";
    min_opt->description = _("Minimum distance or -1 for no limit");

    upload_opt = G_define_option();
    upload_opt->key = "upload";
    upload_opt->type = TYPE_STRING;
    upload_opt->required = YES;
    upload_opt->multiple = YES;
    upload_opt->options = "cat,dist,to_x,to_y,to_along,to_angle,to_attr";
    upload_opt->description =
	_("Values describing the relation between two nearest features");
    upload_opt->descriptions =
	_("cat;category of the nearest feature;"
	  "dist;minimum distance to nearest feature;"
	  "to_x;x coordinate of the nearest point on 'to' feature;"
	  "to_y;y coordinate of the nearest point on 'to' feature;"
	  "to_along;distance between points/centroids in 'from' map and the linear feature's "
	  "start point in 'to' map, along this linear feature;"
	  "to_angle;angle between the linear feature in 'to' map and the positive x axis, at "
	  "the location of point/centroid in 'from' map, counterclockwise, in radians, which "
	  "is between -PI and PI inclusive;"
	  "to_attr;attribute of nearest feature given by to_column option");
    /*  "from_x - x coordinate of the nearest point on 'from' feature;" */
    /*  "from_y - y coordinate of the nearest point on 'from' feature;" */
    /* "from_along - distance to the nearest point on 'from' feature along linear feature;" */

    column_opt = G_define_standard_option(G_OPT_DB_COLUMN);
    column_opt->required = YES;
    column_opt->multiple = YES;
    column_opt->description =
	_("Column name(s) where values specified by 'upload' option will be uploaded");
    column_opt->guisection = _("From_map");

    to_column_opt = G_define_standard_option(G_OPT_DB_COLUMN);
    to_column_opt->key = "to_column";
    to_column_opt->description =
	_("Column name of nearest feature (used with upload=to_attr)");
    to_column_opt->guisection = _("To");
    
    table_opt = G_define_standard_option(G_OPT_DB_TABLE);
    table_opt->gisprompt = "new_dbtable,dbtable,dbtable";
    table_opt->description =
	_("Name of table created for output when the distance to all flag is used");

    print_flag = G_define_flag();
    print_flag->key = 'p';
    print_flag->label =
	_("Print output to stdout, don't update attribute table");
    print_flag->description =
	_("First column is always category of 'from' feature called from_cat");

    all_flag = G_define_flag();
    all_flag->key = 'a';
    all_flag->label =
	_("Calculate distances to all features within the threshold");
    all_flag->description = _("The output is written to stdout but may be uploaded "
                              "to a new table created by this module. "
			      "From categories are may be multiple.");	/* huh? */

    /* GUI dependency */
    from_opt->guidependency = G_store(from_field_opt->key);
    sprintf(buf1, "%s,%s", to_field_opt->key, to_column_opt->key);
    to_opt->guidependency = G_store(buf1);
    to_field_opt->guidependency = G_store(to_column_opt->key);

    if (G_parser(argc, argv))
	exit(EXIT_FAILURE);

    from_type = Vect_option_to_types(from_type_opt);
    to_type = Vect_option_to_types(to_type_opt);

    from_field = atoi(from_field_opt->answer);

    max = atof(max_opt->answer);
    min = atof(min_opt->answer);

    if (all_flag->answer)
	all = 1;

    /* Read upload and column options */
    /* count */
    i = 0;
    while (upload_opt->answers[i])
	i++;
    if (strcmp(from_opt->answer, to_opt->answer) == 0 &&
	all && !table_opt->answer && i == 1)
	print_as_matrix = 1;

    /* alloc */
    Upload = (UPLOAD *) G_calloc(i + 1, sizeof(UPLOAD));
    /* read upload */
    i = 0;
    while (upload_opt->answers[i]) {
	if (strcmp(upload_opt->answers[i], "cat") == 0)
	    Upload[i].upload = CAT;
	else if (strcmp(upload_opt->answers[i], "from_x") == 0)
	    Upload[i].upload = FROM_X;
	else if (strcmp(upload_opt->answers[i], "from_y") == 0)
	    Upload[i].upload = FROM_Y;
	else if (strcmp(upload_opt->answers[i], "to_x") == 0)
	    Upload[i].upload = TO_X;
	else if (strcmp(upload_opt->answers[i], "to_y") == 0)
	    Upload[i].upload = TO_Y;
	else if (strcmp(upload_opt->answers[i], "from_along") == 0)
	    Upload[i].upload = FROM_ALONG;
	else if (strcmp(upload_opt->answers[i], "to_along") == 0)
	    Upload[i].upload = TO_ALONG;
	else if (strcmp(upload_opt->answers[i], "dist") == 0)
	    Upload[i].upload = DIST;
	else if (strcmp(upload_opt->answers[i], "to_angle") == 0)
	    Upload[i].upload = TO_ANGLE;
	else if (strcmp(upload_opt->answers[i], "to_attr") == 0) {
	    if (!(to_column_opt->answer)) {
		G_fatal_error(_("to_column option missing"));
	    }
	    Upload[i].upload = TO_ATTR;
	}

	i++;
    }
    Upload[i].upload = END;
    /* read columns */
    i = 0;
    while (column_opt->answers[i]) {
	if (Upload[i].upload == END) {
	    G_warning(_("Too many column names"));
	    break;
	}
	Upload[i].column = G_store(column_opt->answers[i]);
	i++;
    }
    if (Upload[i].upload != END)
	G_fatal_error(_("Not enough column names"));

    /* Open 'from' vector */
    Vect_set_open_level(2);
    Vect_open_old(&From, from_opt->answer, G_mapset());

    /* Open 'to' vector */
    Vect_set_open_level(2);
    Vect_open_old2(&To, to_opt->answer, "", to_field_opt->answer);

    to_field = Vect_get_field_number(&To, to_field_opt->answer);

    /* Open output vector */
    if (out_opt->answer) {
	Vect_open_new(&Out, out_opt->answer, WITHOUT_Z);
	Vect_hist_command(&Out);
	Outp = &Out;
    }
    else {
	Outp = NULL;
    }

    /* TODO: add maxdist = -1 to Vect_select_ !!! */
    /* Calc maxdist */
    n_max_steps = 1;
    if (max != 0) {
	struct bound_box fbox, tbox;
	double dx, dy, dz, tmp_max;
	int n_features = 0;

	Vect_get_map_box(&From, &fbox);
	Vect_get_map_box(&To, &tbox);

	Vect_box_extend(&fbox, &tbox);

	dx = fbox.E - fbox.W;
	dy = fbox.N - fbox.S;
	if (Vect_is_3d(&From))
	    dz = fbox.T - fbox.B;
	else
	    dz = 0.0;

	tmp_max = sqrt(dx * dx + dy * dy + dz * dz);
	if (max < 0)
	    max = tmp_max;

	/* how to determine a reasonable number of steps to increase the search box? */
	/* with max > 0 but max <<< tmp_max, 2 steps are sufficient, first 0 then max
	 * a reasonable number of steps also depends on the number of features in To
	 * e.g. only one area in To, no need to step */
	nto = Vect_get_num_lines(&To);
	for (tline = 1; tline <= nto; tline++) {
	    /* TODO: Vect_get_line_type() */
	    n_features += ((to_type & To.plus.Line[tline]->type) != 0);
	}
	if (to_type & GV_AREA) {
	    if (Vect_get_num_areas(&To) > n_features)
		n_features = Vect_get_num_areas(&To);
	}
	if (n_features == 0)
	    G_fatal_error(_("No features of selected type in To vector <%s>"),
			    to_opt->answer);
	n_max_steps = sqrt(n_features) * max / tmp_max;
	/* max 9 steps from testing */
	if (n_max_steps > 9)
	    n_max_steps = 9;
	if (n_max_steps < 2)
	    n_max_steps = 2;
	if (n_max_steps > n_features)
	    n_max_steps = n_features;

	G_debug(2, "max = %f", max);
	G_debug(2, "maximum reasonable search distance = %f", tmp_max);
	G_debug(2, "n_features = %d", n_features);
	G_debug(2, "n_max_steps = %d", n_max_steps);
    }

    if (min > max)
	G_fatal_error("dmin can not be larger than dmax");

    if (n_max_steps > 1) {
	/* set up steps to increase search box */
	max_step = G_malloc(n_max_steps * sizeof(double));
	/* first step always 0 */
	max_step[0] = 0;

	for (curr_step = 1; curr_step < n_max_steps - 1; curr_step++) {
	    /* for 9 steps, this would be max / [128, 64, 32, 16, 8, 4, 2] */
	    max_step[curr_step] = max / (2 << (n_max_steps - 1 - curr_step));
	}
	/* last step always max */
	max_step[n_max_steps - 1] = max;
    }
    else {
	max_step = G_malloc(sizeof(double));
	max_step[0] = max;
    }

    /* Open database driver */
    db_init_string(&stmt);
    db_init_string(&dbstr);
    driver = NULL;
    if (!print_flag->answer) {

	if (!all) {
	    Fi = Vect_get_field(&From, from_field);
	    if (Fi == NULL)
		G_fatal_error(_("Database connection not defined for layer %d"),
			      from_field);

	    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);

	    /* check if column exists */
	    i = 0;
	    while (column_opt->answers[i]) {
		db_get_column(driver, Fi->table, column_opt->answers[i],
			      &column);
		if (column) {
		    db_free_column(column);
		    column = NULL;
		}
		else {
		    G_fatal_error(_("Column <%s> not found in table <%s>"),
				  column_opt->answers[i], Fi->table);
		}
		i++;
	    }
	}
	else {
	    driver = db_start_driver_open_database(NULL, NULL);
	    if (driver == NULL)
		G_fatal_error(_("Unable to open default database"));
	}
    }

    to_driver = NULL;
    if (to_column_opt->answer) {
	toFi = Vect_get_field(&To, to_field);
	if (toFi == NULL)
	    G_fatal_error(_("Database connection not defined for layer %d"),
			  to_field);

	to_driver =
	    db_start_driver_open_database(toFi->driver, toFi->database);
	if (to_driver == NULL)
	    G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
			  toFi->database, toFi->driver);

	/* check if to_column exists */
	db_get_column(to_driver, toFi->table, to_column_opt->answer, &column);
	if (column) {
	    db_free_column(column);
	    column = NULL;
	}
	else {
	    G_fatal_error(_("Column <%s> not found in table <%s>"),
			  to_column_opt->answer, toFi->table);
	}

	/* Check column types */
	if (!print_flag->answer && !all) {
	    char *fcname = NULL;
	    int fctype, tctype;

	    i = 0;
	    while (column_opt->answers[i]) {
		if (Upload[i].upload == TO_ATTR) {
		    fcname = column_opt->answers[i];
		    break;
		}
		i++;
	    }

	    if (fcname) {
		fctype = db_column_Ctype(driver, Fi->table, fcname);
		tctype =
		    db_column_Ctype(to_driver, toFi->table,
				    to_column_opt->answer);

		if (((tctype == DB_C_TYPE_STRING ||
		      tctype == DB_C_TYPE_DATETIME)
		     && (fctype == DB_C_TYPE_INT ||
			 fctype == DB_C_TYPE_DOUBLE)) ||
		    ((tctype == DB_C_TYPE_INT || tctype == DB_C_TYPE_DOUBLE)
		     && (fctype == DB_C_TYPE_STRING ||
			 fctype == DB_C_TYPE_DATETIME))
		    ) {
		    G_fatal_error(_("Incompatible column types"));
		}
	    }
	}
    }

    FPoints = Vect_new_line_struct();
    TPoints = Vect_new_line_struct();
    FCats = Vect_new_cats_struct();
    TCats = Vect_new_cats_struct();
    List = Vect_new_boxlist(1);

    /* Allocate space ( may be more than needed (duplicate cats and elements without cats) ) */
    nfrom = Vect_get_num_lines(&From);
    nto = Vect_get_num_lines(&To);
    if (all) {
	/* Attention with space for all, it can easily run out of memory */
	anear = 2 * nfrom;
	Near = (NEAR *) G_calloc(anear, sizeof(NEAR));
    }
    else {
	Near = (NEAR *) G_calloc(nfrom, sizeof(NEAR));
    }

    /* Read all cats from 'from' */
    if (!all) {
	nfcats = 0;
	for (i = 1; i <= nfrom; i++) {
	    ftype = Vect_read_line(&From, NULL, FCats, i);

	    /* This keeps also categories of areas for future (if area s in from_type) */
	    if (!(ftype & from_type) &&
		(ftype != GV_CENTROID || !(from_type & GV_AREA)))
		continue;

	    Vect_cat_get(FCats, from_field, &fcat);
	    if (fcat < 0)
		continue;
	    Near[nfcats].from_cat = fcat;
	    nfcats++;
	}
	G_debug(1, "%d cats loaded from vector (including duplicates)",
		nfcats);
	/* Sort by cats and remove duplicates */
	qsort((void *)Near, nfcats, sizeof(NEAR), cmp_near);

	/* remove duplicates */
	for (i = 1; i < nfcats; i++) {
	    if (Near[i].from_cat == Near[i - 1].from_cat) {
		for (j = i; j < nfcats - 1; j++) {
		    Near[j].from_cat = Near[j + 1].from_cat;
		}
		nfcats--;
	    }
	}

	G_debug(1, "%d cats loaded from vector (unique)", nfcats);
    }

    /* Go through all lines in 'from' and find nearest in 'to' for each */
    /* Note: as from_type is restricted to GV_POINTS (for now) everything is simple */

    count = 0;			/* count of distances in 'all' mode */
    /* Find nearest lines */
    if (to_type & (GV_POINTS | GV_LINES)) {
	struct line_pnts *LLPoints;

	if (G_projection() == PROJECTION_LL) {
	    LLPoints = Vect_new_line_struct();
	}
	else {
	    LLPoints = NULL;
	}
	G_message(_("Finding nearest feature..."));
	for (fline = 1; fline <= nfrom; fline++) {
	    int tmp_tcat;
	    double tmp_tangle, tangle;
	    double tmp_min = (min < 0 ? 0 : min);
	    double box_edge = 0;
	    int done = 0;

	    curr_step = 0;

	    G_debug(3, "fline = %d", fline);
	    G_percent(fline, nfrom, 2);
	    ftype = Vect_read_line(&From, FPoints, FCats, fline);
	    if (!(ftype & from_type))
		continue;

	    Vect_cat_get(FCats, from_field, &fcat);
	    if (fcat < 0 && !all)
		continue;

	    while (!done) {
		done = 1;

		if (!all) {
		    /* enlarge search box until we get a hit */
		    /* the objective is to enlarge the search box
		     * in the first iterations just a little bit
		     * to keep the number of hits low */
		    Vect_reset_boxlist(List);
		    while (curr_step < n_max_steps) {
			box_edge = max_step[curr_step];

			if (box_edge < tmp_min)
			    continue;
			
			box.E = FPoints->x[0] + box_edge;
			box.W = FPoints->x[0] - box_edge;
			box.N = FPoints->y[0] + box_edge;
			box.S = FPoints->y[0] - box_edge;
			box.T = PORT_DOUBLE_MAX;
			box.B = -PORT_DOUBLE_MAX;

			Vect_select_lines_by_box(&To, &box, to_type, List);

			curr_step++;
			if (List->n_values > 0)
			    break;
		    }
		}
		else {
		    box.E = FPoints->x[0] + max;
		    box.W = FPoints->x[0] - max;
		    box.N = FPoints->y[0] + max;
		    box.S = FPoints->y[0] - max;
		    box.T = PORT_DOUBLE_MAX;
		    box.B = -PORT_DOUBLE_MAX;

		    Vect_select_lines_by_box(&To, &box, to_type, List);
		}

		G_debug(3, "  %d lines in box", List->n_values);

		tline = 0;
		dist = PORT_DOUBLE_MAX;
		for (i = 0; i < List->n_values; i++) {
		    tmp_tcat = -1;
		    Vect_read_line(&To, TPoints, TCats, List->id[i]);

		    tseg =
			Vect_line_distance(TPoints, FPoints->x[0], FPoints->y[0],
					   FPoints->z[0], (Vect_is_3d(&From) &&
							   Vect_is_3d(&To)) ?
					   WITH_Z : WITHOUT_Z, &tmp_tx, &tmp_ty,
					   &tmp_tz, &tmp_dist, NULL, &tmp_talong);

		    Vect_point_on_line(TPoints, tmp_talong, NULL, NULL, NULL,
				       &tmp_tangle, NULL);

		    if (tmp_dist > max || tmp_dist < min)
			continue;	/* not in threshold */

		    /* TODO: more cats of the same field */
		    Vect_cat_get(TCats, to_field, &tmp_tcat);
		    if (G_projection() == PROJECTION_LL) {
			/* calculate distances in meters not degrees (only 2D) */
			Vect_reset_line(LLPoints);
			Vect_append_point(LLPoints, FPoints->x[0], FPoints->y[0],
					  FPoints->z[0]);
			Vect_append_point(LLPoints, tmp_tx, tmp_ty, tmp_tz);
			tmp_dist = Vect_line_geodesic_length(LLPoints);
			Vect_reset_line(LLPoints);
			for (k = 0; k < tseg; k++)
			    Vect_append_point(LLPoints, TPoints->x[k],
					      TPoints->y[k], TPoints->z[k]);
			Vect_append_point(LLPoints, tmp_tx, tmp_ty, tmp_tz);
			tmp_talong = Vect_line_geodesic_length(LLPoints);
		    }

		    G_debug(4, "  tmp_dist = %f tmp_tcat = %d", tmp_dist,
			    tmp_tcat);

		    if (all) {
			if (anear <= count) {
			    anear += 10 + nfrom / 10;
			    Near = (NEAR *) G_realloc(Near, anear * sizeof(NEAR));
			}
			near = &(Near[count]);

			/* store info about relation */
			near->from_cat = fcat;
			near->to_cat = tmp_tcat;	/* -1 is OK */
			near->dist = tmp_dist;
			near->from_x = FPoints->x[0];
			near->from_y = FPoints->y[0];
			near->from_z = FPoints->z[0];
			near->to_x = tmp_tx;
			near->to_y = tmp_ty;
			near->to_z = tmp_tz;
			near->to_along = tmp_talong;	/* 0 for points */
			near->to_angle = tmp_tangle;
			near->count++;
			count++;
		    }
		    else {
			if (tline == 0 || (tmp_dist < dist)) {
			    tline = List->id[i];
			    tcat = tmp_tcat;
			    dist = tmp_dist;
			    tx = tmp_tx;
			    ty = tmp_ty;
			    tz = tmp_tz;
			    talong = tmp_talong;
			    tangle = tmp_tangle;
			}
		    }
		}

		G_debug(4, "  dist = %f", dist);

		if (curr_step < n_max_steps) {
		    /* enlarging the search box is possible */
		    if (tline > 0 && dist > box_edge) {
			/* line found but distance > search edge:
			 * line bbox overlaps with search box, line itself is outside search box */
			done = 0;
		    }
		    else if (tline == 0) {
			/* no line within max dist, but search box can still be enlarged */
			done = 0;
		    }
		}
		if (done && !all && tline > 0) {
		    /* find near by cat */
		    near =
			(NEAR *) bsearch((void *)&fcat, Near, nfcats,
					 sizeof(NEAR), cmp_near);

		    G_debug(4, "  near.from_cat = %d near.count = %d",
			    near->from_cat, near->count);
		    /* store info about relation */
		    if (near->count == 0 || near->dist > dist) {
			near->to_cat = tcat;	/* -1 is OK */
			near->dist = dist;
			near->from_x = FPoints->x[0];
			near->from_y = FPoints->y[0];
			near->from_z = FPoints->z[0];
			near->to_x = tx;
			near->to_y = ty;
			near->to_z = tz;
			near->to_along = talong;	/* 0 for points */
			near->to_angle = tangle;
		    }
		    near->count++;
		}
	    } /* done */
	} /* next feature */
	if (LLPoints) {
	    Vect_destroy_line_struct(LLPoints);
	}
    }

    /* Find nearest areas */
    if (to_type & GV_AREA) {
	
	G_message(_("Finding nearest areas..."));
	for (fline = 1; fline <= nfrom; fline++) {
	    double tmp_min = (min < 0 ? 0 : min);
	    double box_edge = 0;
	    int done = 0;
	    
	    curr_step = 0;

	    G_debug(3, "fline = %d", fline);
	    G_percent(fline, nfrom, 2);
	    ftype = Vect_read_line(&From, FPoints, FCats, fline);
	    if (!(ftype & from_type))
		continue;

	    Vect_cat_get(FCats, from_field, &fcat);
	    if (fcat < 0 && !all)
		continue;

	    while (!done) {
		done = 1;

		if (!all) {
		    /* enlarge search box until we get a hit */
		    /* the objective is to enlarge the search box
		     * in the first iterations just a little bit
		     * to keep the number of hits low */
		    Vect_reset_boxlist(List);
		    while (curr_step < n_max_steps) {
			box_edge = max_step[curr_step];

			if (box_edge < tmp_min)
			    continue;
			
			box.E = FPoints->x[0] + box_edge;
			box.W = FPoints->x[0] - box_edge;
			box.N = FPoints->y[0] + box_edge;
			box.S = FPoints->y[0] - box_edge;
			box.T = PORT_DOUBLE_MAX;
			box.B = -PORT_DOUBLE_MAX;

			Vect_select_areas_by_box(&To, &box, List);

			curr_step++;
			if (List->n_values > 0)
			    break;
		    }
		}
		else {
		    box.E = FPoints->x[0] + max;
		    box.W = FPoints->x[0] - max;
		    box.N = FPoints->y[0] + max;
		    box.S = FPoints->y[0] - max;
		    box.T = PORT_DOUBLE_MAX;
		    box.B = -PORT_DOUBLE_MAX;

		    Vect_select_areas_by_box(&To, &box, List);
		}

		G_debug(4, "%d areas selected by box", List->n_values);

		/* For each area in box check the distance */
		tarea = 0;
		dist = PORT_DOUBLE_MAX;
		for (i = 0; i < List->n_values; i++) {
		    int tmp_tcat;

		    area = List->id[i];
		    G_debug(4, "%d: area %d", i, area);
		    Vect_get_area_points(&To, area, TPoints);

		    /* Find the distance to this area */
		    if (Vect_point_in_area(FPoints->x[0], FPoints->y[0], &To, area, List->box[i])) {	/* in area */
			tmp_dist = 0;
			tmp_tx = FPoints->x[0];
			tmp_ty = FPoints->y[0];
		    }
		    else if (Vect_point_in_poly(FPoints->x[0], FPoints->y[0], TPoints) > 0) {	/* in isle */
			nisles = Vect_get_area_num_isles(&To, area);
			for (j = 0; j < nisles; j++) {
			    double tmp2_dist, tmp2_tx, tmp2_ty;

			    isle = Vect_get_area_isle(&To, area, j);
			    Vect_get_isle_points(&To, isle, TPoints);
			    Vect_line_distance(TPoints, FPoints->x[0],
					       FPoints->y[0], FPoints->z[0],
					       WITHOUT_Z, &tmp2_tx, &tmp2_ty,
					       NULL, &tmp2_dist, NULL, NULL);

			    if (j == 0 || tmp2_dist < tmp_dist) {
				tmp_dist = tmp2_dist;
				tmp_tx = tmp2_tx;
				tmp_ty = tmp2_ty;
			    }
			}
		    }
		    else {		/* outside area */
			Vect_line_distance(TPoints, FPoints->x[0], FPoints->y[0],
					   FPoints->z[0], WITHOUT_Z, &tmp_tx,
					   &tmp_ty, NULL, &tmp_dist, NULL, NULL);

		    }
		    if (tmp_dist > max || tmp_dist < min)
			continue;	/* not in threshold */
		    Vect_get_area_cats(&To, area, TCats);
		    tmp_tcat = -1;
		    /* TODO: all cats of given field ? */
		    for (j = 0; j < TCats->n_cats; j++) {
			if (TCats->field[j] == to_field) {
			    if (tmp_tcat >= 0)
				G_warning(_("More cats found in to_layer (area=%d)"),
					  area);
			    tmp_tcat = TCats->cat[j];
			}
		    }

		    G_debug(4, "  tmp_dist = %f tmp_tcat = %d", tmp_dist,
			    tmp_tcat);

		    if (all) {
			if (anear <= count) {
			    anear += 10 + nfrom / 10;
			    Near = (NEAR *) G_realloc(Near, anear * sizeof(NEAR));
			}
			near = &(Near[count]);

			/* store info about relation */
			near->from_cat = fcat;
			near->to_cat = tmp_tcat;	/* -1 is OK */
			near->dist = tmp_dist;
			near->from_x = FPoints->x[0];
			near->from_y = FPoints->y[0];
			near->to_x = tmp_tx;
			near->to_y = tmp_ty;
			near->to_along = 0;	/* nonsense for areas */
			near->to_angle = 0;	/* not supported for areas */
			near->count++;
			count++;
		    }
		    else if (tarea == 0 || tmp_dist < dist) {
			tarea = area;
			tcat = tmp_tcat;
			dist = tmp_dist;
			tx = tmp_tx;
			ty = tmp_ty;
		    }
		}

		if (curr_step < n_max_steps) {
		    /* enlarging the search box is possible */
		    if (tarea > 0 && dist > box_edge) {
			/* area found but distance > search edge:
			 * area bbox overlaps with search box, area itself is outside search box */
			done = 0;
		    }
		    else if (tarea == 0) {
			/* no area within max dist, but search box can still be enlarged */
			done = 0;
		    }
		}
		if (done && !all && tarea > 0) {
		    /* find near by cat */
		    near =
			(NEAR *) bsearch((void *)&fcat, Near, nfcats,
					 sizeof(NEAR), cmp_near);

		    G_debug(4, "near.from_cat = %d near.count = %d dist = %f",
			    near->from_cat, near->count, near->dist);

		    /* store info about relation */
		    if (near->count == 0 || near->dist > dist) {
			near->to_cat = tcat;	/* -1 is OK */
			near->dist = dist;
			near->from_x = FPoints->x[0];
			near->from_y = FPoints->y[0];
			near->to_x = tx;
			near->to_y = ty;
			near->to_along = 0;	/* nonsense for areas */
			near->to_angle = 0;	/* not supported for areas */
		    }
		    near->count++;
		}
	    } /* done */
	} /* next feature */
    }

    G_debug(3, "count = %d", count);

    /* Update database / print to stdout / create output map */
    if (print_flag->answer) {	/* print header */
	fprintf(stdout, "from_cat");
	i = 0;
	while (Upload[i].upload != END) {
	    fprintf(stdout, "|%s", Upload[i].column);
	    i++;
	}
	fprintf(stdout, "\n");
    }
    else if (all && table_opt->answer) {	/* create new table */
	db_set_string(&stmt, "create table ");
	db_append_string(&stmt, table_opt->answer);
	db_append_string(&stmt, " (from_cat integer");

	j = 0;
	while (Upload[j].upload != END) {
	    db_append_string(&stmt, ", ");

	    switch (Upload[j].upload) {
	    case CAT:
		sprintf(buf2, "%s integer", Upload[j].column);
		break;
	    case DIST:
	    case FROM_X:
	    case FROM_Y:
	    case TO_X:
	    case TO_Y:
	    case FROM_ALONG:
	    case TO_ALONG:
	    case TO_ANGLE:
		sprintf(buf2, "%s double precision", Upload[j].column);
	    }
	    db_append_string(&stmt, buf2);
	    j++;
	}
	db_append_string(&stmt, " )");
	G_debug(3, "SQL: %s", db_get_string(&stmt));

	if (db_execute_immediate(driver, &stmt) != DB_OK)
	    G_fatal_error(_("Unable to create table: '%s'"),
			  db_get_string(&stmt));

	if (db_grant_on_table(driver, table_opt->answer, DB_PRIV_SELECT,
			      DB_GROUP | DB_PUBLIC) != DB_OK)
	    G_fatal_error(_("Unable to grant privileges on table <%s>"),
			  table_opt->answer);

    }
    else if (!all) {		/* read existing cats from table */
	ncatexist =
	    db_select_int(driver, Fi->table, Fi->key, NULL, &catexist);
	G_debug(1, "%d cats selected from the table", ncatexist);
    }
    update_ok = update_err = update_exist = update_notexist = update_dupl =
	update_notfound = 0;

    if (!all) {
	count = nfcats;
    }
    else if (print_as_matrix) {
	qsort((void *)Near, count, sizeof(NEAR), cmp_near_to);
    }

    if (driver)
	db_begin_transaction(driver);

    /* select 'to' attributes */
    if (to_column_opt->answer) {
	int nrec;

	db_CatValArray_init(&cvarr);
	nrec = db_select_CatValArray(to_driver, toFi->table, toFi->key,
				     to_column_opt->answer, NULL, &cvarr);
	G_debug(3, "selected values = %d", nrec);

	if (cvarr.ctype == DB_C_TYPE_DATETIME) {
	    G_warning(_("DATETIME type not yet supported, no attributes will be uploaded"));
	}
	db_close_database_shutdown_driver(to_driver);
    }

    if (!(print_flag->answer || (all && !table_opt->answer))) /* no printing */
	G_message("Update database...");

    for (i = 0; i < count; i++) {
	dbCatVal *catval = 0;

	if (!(print_flag->answer || (all && !table_opt->answer))) /* no printing */
	    G_percent(i, count, 1);

	/* Write line connecting nearest points */
	if (Outp != NULL) {
	    Vect_reset_line(FPoints);
	    Vect_reset_cats(FCats);

	    Vect_append_point(FPoints, Near[i].from_x, Near[i].from_y, 0);

	    if (Near[i].dist == 0) {
		Vect_write_line(Outp, GV_POINT, FPoints, FCats);
	    }
	    else {
		Vect_append_point(FPoints, Near[i].to_x, Near[i].to_y, 0);
		Vect_write_line(Outp, GV_LINE, FPoints, FCats);
	    }

	}

	if (Near[i].count > 1)
	    update_dupl++;
	if (Near[i].count == 0)
	    update_notfound++;

	if (to_column_opt->answer && Near[i].count > 0) {
	    db_CatValArray_get_value(&cvarr, Near[i].to_cat, &catval);
	}

	if (print_flag->answer || (all && !table_opt->answer)) {	/* print only */
	    /*
	       input and output is the same &&
	       calculate distances &&
	       only one upload option given ->
	       print as a matrix
	     */
	    if (print_as_matrix) {
		if (i == 0) {
		    for (j = 0; j < nfrom; j++) {
			if (j == 0)
			    fprintf(stdout, " ");
			fprintf(stdout, "|%d", Near[j].to_cat);
		    }
		    fprintf(stdout, "\n");
		}
		if (i % nfrom == 0) {
		    fprintf(stdout, "%d", Near[i].from_cat);
		    for (j = 0; j < nfrom; j++) {
			print_upload(Near, Upload, i + j, &cvarr, catval);
		    }
		    fprintf(stdout, "\n");
		}
	    }
	    else {
		fprintf(stdout, "%d", Near[i].from_cat);
		print_upload(Near, Upload, i, &cvarr, catval);
		fprintf(stdout, "\n");
	    }
	}
	else if (all) {		/* insert new record */
	    sprintf(buf1, "insert into %s values ( %d ", table_opt->answer,
		    Near[i].from_cat);
	    db_set_string(&stmt, buf1);

	    j = 0;
	    while (Upload[j].upload != END) {
		db_append_string(&stmt, ",");

		switch (Upload[j].upload) {
		case CAT:
		    sprintf(buf2, " %d", Near[i].to_cat);
		    break;
		case DIST:
		    sprintf(buf2, " %f", Near[i].dist);
		    break;
		case FROM_X:
		    sprintf(buf2, " %f", Near[i].from_x);
		    break;
		case FROM_Y:
		    sprintf(buf2, " %f", Near[i].from_y);
		    break;
		case TO_X:
		    sprintf(buf2, " %f", Near[i].to_x);
		    break;
		case TO_Y:
		    sprintf(buf2, " %f", Near[i].to_y);
		    break;
		case FROM_ALONG:
		    sprintf(buf2, " %f", Near[i].from_along);
		    break;
		case TO_ALONG:
		    sprintf(buf2, " %f", Near[i].to_along);
		    break;
		case TO_ANGLE:
		    sprintf(buf2, " %f", Near[i].to_angle);
		    break;
		case TO_ATTR:
		    if (catval) {
			switch (cvarr.ctype) {
			case DB_C_TYPE_INT:
			    sprintf(buf2, " %d", catval->val.i);
			    break;

			case DB_C_TYPE_DOUBLE:
			    sprintf(buf2, " %.15e", catval->val.d);
			    break;

			case DB_C_TYPE_STRING:
			    db_set_string(&dbstr,
					  db_get_string(catval->val.s));
			    db_double_quote_string(&dbstr);
			    sprintf(buf2, " '%s'", db_get_string(&dbstr));
			    break;

			case DB_C_TYPE_DATETIME:
			    /* TODO: formating datetime */
			    sprintf(buf2, " null");
			    break;
			}
		    }
		    else {
			sprintf(buf2, " null");
		    }
		    break;
		}
		db_append_string(&stmt, buf2);
		j++;
	    }
	    db_append_string(&stmt, " )");
	    G_debug(3, "SQL: %s", db_get_string(&stmt));
	    if (db_execute_immediate(driver, &stmt) == DB_OK) {
		update_ok++;
	    }
	    else {
		update_err++;
	    }
	}
	else {			/* update table */
	    /* check if exists in table */
	    cex =
		(int *)bsearch((void *)&(Near[i].from_cat), catexist,
			       ncatexist, sizeof(int), cmp_exist);
	    if (cex == NULL) {	/* cat does not exist in DB */
		update_notexist++;
		continue;
	    }
	    update_exist++;

	    sprintf(buf1, "update %s set", Fi->table);
	    db_set_string(&stmt, buf1);

	    j = 0;
	    while (Upload[j].upload != END) {
		if (j > 0)
		    db_append_string(&stmt, ",");

		sprintf(buf2, " %s =", Upload[j].column);
		db_append_string(&stmt, buf2);

		if (Near[i].count == 0) {	/* no nearest found */
		    db_append_string(&stmt, " null");
		}
		else {
		    switch (Upload[j].upload) {
		    case CAT:
			if (Near[i].to_cat > 0)
			    sprintf(buf2, " %d", Near[i].to_cat);
			else
			    sprintf(buf2, " null");
			break;
		    case DIST:
			sprintf(buf2, " %f", Near[i].dist);
			break;
		    case FROM_X:
			sprintf(buf2, " %f", Near[i].from_x);
			break;
		    case FROM_Y:
			sprintf(buf2, " %f", Near[i].from_y);
			break;
		    case TO_X:
			sprintf(buf2, " %f", Near[i].to_x);
			break;
		    case TO_Y:
			sprintf(buf2, " %f", Near[i].to_y);
			break;
		    case FROM_ALONG:
			sprintf(buf2, " %f", Near[i].from_along);
			break;
		    case TO_ALONG:
			sprintf(buf2, " %f", Near[i].to_along);
			break;
		    case TO_ANGLE:
			sprintf(buf2, " %f", Near[i].to_angle);
			break;
		    case TO_ATTR:
			if (catval) {
			    switch (cvarr.ctype) {
			    case DB_C_TYPE_INT:
				sprintf(buf2, " %d", catval->val.i);
				break;

			    case DB_C_TYPE_DOUBLE:
				sprintf(buf2, " %.15e", catval->val.d);
				break;

			    case DB_C_TYPE_STRING:
				db_set_string(&dbstr,
					      db_get_string(catval->val.s));
				db_double_quote_string(&dbstr);
				sprintf(buf2, " '%s'", db_get_string(&dbstr));
				break;

			    case DB_C_TYPE_DATETIME:
				/* TODO: formating datetime */
				sprintf(buf2, " null");
				break;
			    }
			}
			else {
			    sprintf(buf2, " null");
			}
			break;
		    }
		    db_append_string(&stmt, buf2);
		}
		j++;
	    }
	    sprintf(buf2, " where %s = %d", Fi->key, Near[i].from_cat);
	    db_append_string(&stmt, buf2);
	    G_debug(2, "SQL: %s", db_get_string(&stmt));
	    if (db_execute_immediate(driver, &stmt) == DB_OK) {
		update_ok++;
	    }
	    else {
		update_err++;
	    }
	}
    }
    G_percent(count, count, 1);

    if (driver)
	db_commit_transaction(driver);

    /* print stats */
    if (update_dupl > 0)
	G_message(_("%d categories with more than 1 feature in vector map <%s>"),
		  update_dupl, from_opt->answer);
    if (update_notfound > 0)
	G_message(_("%d categories - no nearest feature found"),
		  update_notfound);

    if (!print_flag->answer) {
	db_close_database_shutdown_driver(driver);
	db_free_string(&stmt);

	/* print stats */
	if (all && table_opt->answer) {
	    G_message(_("%d distances calculated"), count);
	    G_message(_("%d records inserted"), update_ok);
	    if (update_err > 0)
		G_message(_("%d insert errors"), update_err);
	}
	else if (!all) {
	    if (nfcats > 0)
		G_message(_("%d categories read from the map"), nfcats);
	    if (ncatexist > 0)
		G_message(_("%d categories exist in the table"), ncatexist);
	    if (update_exist > 0)
		G_message(_("%d categories read from the map exist in the table"),
			  update_exist);
	    if (update_notexist > 0)
		G_message(_("%d categories read from the map don't exist in the table"),
			  update_notexist);
	    G_message(_("%d records updated"), update_ok);
	    if (update_err > 0)
		G_message(_("%d update errors"), update_err);

	    G_free(catexist);
	}

	Vect_set_db_updated(&From);
    }

    Vect_close(&From);
    if (Outp != NULL) {
	Vect_build(Outp);
	Vect_close(Outp);
    }

    G_done_msg(" ");

    exit(EXIT_SUCCESS);
}
Exemplo n.º 12
0
int main(int argc, char *argv[])
{
    int i, j, precision, field;
    int do_attr = 0, attr_cols[8], attr_size = 0, db_open = 0, cnt = 0;

    double width, radius;
    struct Option *in_opt, *out_opt, *prec_opt, *type_opt, *attr_opt,
               *field_opt;
    struct GModule *module;
    struct Map_info In;
    struct bound_box box;

    /* vector */
    struct line_pnts *Points;
    struct line_cats *Cats;

    /* attribs */
    dbDriver *Driver = NULL;
    dbHandle handle;
    dbTable *Table;
    dbString dbstring;
    struct field_info *Fi;

    /* init */
    G_gisinit(argv[0]);

    /* parse command-line */
    module = G_define_module();
    module->description = _("Exports a vector map to SVG file.");
    G_add_keyword(_("vector"));
    G_add_keyword(_("export"));

    in_opt = G_define_standard_option(G_OPT_V_INPUT);

    field_opt = G_define_standard_option(G_OPT_V_FIELD_ALL);

    out_opt = G_define_standard_option(G_OPT_F_OUTPUT);
    out_opt->description = _("Name for SVG output file");

    type_opt = G_define_option();
    type_opt->key = "type";
    type_opt->type = TYPE_STRING;
    type_opt->required = YES;
    type_opt->multiple = NO;
    type_opt->answer = "poly";
    type_opt->options = "poly,line,point";
    type_opt->label = _("Output type");
    type_opt->description = _("Defines which feature-type will be extracted");

    prec_opt = G_define_option();
    prec_opt->key = "precision";
    prec_opt->type = TYPE_INTEGER;
    prec_opt->required = NO;
    prec_opt->answer = "6";
    prec_opt->multiple = NO;
    prec_opt->description = _("Coordinate precision");

    attr_opt = G_define_standard_option(G_OPT_DB_COLUMNS);
    attr_opt->key = "attribute";
    attr_opt->required = NO;
    attr_opt->multiple = YES;
    attr_opt->description = _("Attribute(s) to include in output SVG");

    if (G_parser(argc, argv))
        exit(EXIT_FAILURE);

    Points = Vect_new_line_struct();
    Cats = Vect_new_cats_struct();

    /* override coordinate precision if any */
    precision = atof(prec_opt->answer);
    if (precision < 0) {
        G_fatal_error(_("Precision must not be negative"));
    }
    if (precision > 15) {
        G_fatal_error(_("Precision must not be higher than 15"));
    }

    /* open input vector */
    Vect_set_open_level(2);
    Vect_open_old2(&In, in_opt->answer, "", field_opt->answer);

    /* parse field number */
    field = Vect_get_field_number(&In, field_opt->answer);

    /* open db-driver to attribs */
    db_init_string(&dbstring);

    /* check for requested field */
    Fi = Vect_get_field(&In, field);
    if (Fi != NULL) {
        Driver = db_start_driver(Fi->driver);
        if (Driver == NULL) {
            G_fatal_error(_("Unable to start driver <%s>"), Fi->driver);
        }

        /* open db */
        db_init_handle(&handle);
        db_set_handle(&handle, Fi->database, NULL);
        if (db_open_database(Driver, &handle) != DB_OK) {
            G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
                          Fi->database, Fi->driver);
        }

        db_set_string(&dbstring, Fi->table);
        if (db_describe_table(Driver, &dbstring, &Table) != DB_OK) {
            G_fatal_error(_("Unable to describe table <%s>"), Fi->table);
        }

        /* define column-indices for columns to extract */
        dbColumn *Column;

        for (i = 0; i < db_get_table_number_of_columns(Table); i++) {
            Column = db_get_table_column(Table, i);
            if (attr_opt->answer != NULL) {
                for (j = 0; attr_opt->answers[j] != NULL; j++) {
                    if (G_strcasecmp(attr_opt->answers[j],
                                     db_get_column_name(Column)) == 0) {
                        attr_cols[attr_size] = i;
                        attr_size += 1;
                        break;
                    }
                }
            }
        }
        do_attr = 1;
        db_open = 1;
    }

    /* parse bounding box and define default stroke-width, radius */
    Vect_get_map_box(&In, &box);
    if ((box.E - box.W) >= (box.N - box.S)) {
        radius = (box.E - box.W) * RADIUS_SCALE;
        width = (box.E - box.W) * WIDTH_SCALE;
    }
    else {
        radius = (box.N - box.S) * RADIUS_SCALE;
        width = (box.N - box.S) * WIDTH_SCALE;
    }

    /* open output SVG-file and print SVG-header with viewBox and Namenspaces */
    if ((fpsvg = fopen(out_opt->answer, "w")) == NULL) {
        G_fatal_error(_("Unable to create SVG file <%s>"), out_opt->answer);
    }

    fprintf(fpsvg, "<svg xmlns=\"%s\" xmlns:xlink=\"%s\" xmlns:gg=\"%s\" ",
            SVG_NS, XLINK_NS, GRASS_NS);
    fprintf(fpsvg, "viewBox=\"%.*f %.*f %.*f %.*f\">\n",
            precision, box.W,
            precision, box.N * -1,
            precision, box.E - box.W, precision, box.N - box.S);
    fprintf(fpsvg, "<title>v.out.svg %s %s</title>\n", in_opt->answer,
            out_opt->answer);

    /* extract areas if any or requested */
    if (G_strcasecmp(type_opt->answer, "poly") == 0) {
        if (Vect_get_num_areas(&In) == 0) {
            G_warning(_("No areas found, skipping type=poly"));
        }
        else {
            /* extract area as paths */
            fprintf(fpsvg,
                    " <g id=\"%s\" fill=\"#CCC\" stroke=\"#000\" stroke-width=\"%.*f\" >\n",
                    G_Areas, precision, width);
            for (i = 1; i <= Vect_get_num_areas(&In); i++) {
                /* skip areas without centroid */
                if (Vect_get_area_centroid(&In, i) == 0) {
                    G_warning(_("Skipping area %d without centroid"), i);
                    continue;
                }
                G_percent(i, Vect_get_num_areas(&In), 10);

                /* extract attribs, parse area */
                Vect_get_area_cats(&In, i, Cats);
                fprintf(fpsvg, "  <path ");
                if (Cats->n_cats > 0) {
                    mk_attribs(Cats->cat[0], Fi, Driver, Table, attr_cols,
                               attr_size, do_attr);
                }
                fprintf(fpsvg, "d=\"");

                Vect_get_area_points(&In, i, Points);
                mk_path(Points, precision);

                /* append islands if any within current path */
                for (j = 0; j < Vect_get_area_num_isles(&In, i); j++) {
                    Vect_get_isle_points(&In, Vect_get_area_isle(&In, i, j),
                                         Points);
                    mk_path(Points, precision);
                }
                fprintf(fpsvg, "\" />\n");
                cnt += 1;
            }
            fprintf(fpsvg, " </g>\n");
            G_message(_("Extracted %d areas"), cnt);
        }
    }
    /* extract points if requested */
    if (G_strcasecmp(type_opt->answer, "point") == 0) {
        if (Vect_get_num_primitives(&In, GV_POINTS) == 0) {
            G_warning(_("No points found, skipping type=point"));
        }
        else {
            /* extract points as circles */
            fprintf(fpsvg, " <g id=\"%s\" fill=\"#FC0\" stroke=\"#000\" "
                    "stroke-width=\"%.*f\" >\n", G_Points, precision, width);
            for (i = 1; i <= Vect_get_num_primitives(&In, GV_POINTS); i++) {
                G_percent(i, Vect_get_num_primitives(&In, GV_POINTS), 10);
                Vect_read_line(&In, Points, Cats, i);
                if (field != -1 && !Vect_cat_get(Cats, field, NULL))
                    continue;
                for (j = 0; j < Points->n_points; j++) {
                    fprintf(fpsvg, "  <circle ");
                    if (Cats->n_cats > 0) {
                        mk_attribs(Cats->cat[j], Fi, Driver, Table, attr_cols,
                                   attr_size, do_attr);
                    }
                    fprintf(fpsvg, "cx=\"%.*f\" cy=\"%.*f\" r=\"%.*f\" />\n",
                            precision, Points->x[j],
                            precision, Points->y[j] * -1, precision, radius);
                    cnt += 1;
                }

            }
            fprintf(fpsvg, " </g>\n");
            G_message(_("Extracted %d points"), cnt);
        }
    }
    /* extract lines if requested */
    if (G_strcasecmp(type_opt->answer, "line") == 0) {
        if (Vect_get_num_primitives(&In, GV_LINES) == 0) {
            G_warning(_("No lines found, skipping type=line"));
        }
        else {
            /* extract lines as paths */
            fprintf(fpsvg, " <g id=\"%s\" fill=\"none\" stroke=\"#000\" "
                    "stroke-width=\"%.*f\" >\n", G_Lines, precision, width);
            for (i = 1; i <= Vect_get_num_primitives(&In, GV_LINES); i++) {
                G_percent(i, Vect_get_num_primitives(&In, GV_LINES), 10);
                Vect_read_line(&In, Points, Cats, i);
                fprintf(fpsvg, "  <path ");
                if (Cats->n_cats > 0) {
                    mk_attribs(Cats->cat[0], Fi, Driver, Table,
                               attr_cols, attr_size, do_attr);
                }

                fprintf(fpsvg, "d=\"");
                mk_path(Points, precision);
                fprintf(fpsvg, "\" />\n");
                cnt += 1;
            }
            fprintf(fpsvg, " </g>\n");
            G_message(_("Extracted %d lines"), cnt);
        }
    }
    /* finish code */
    fprintf(fpsvg, "</svg>\n");

    if (db_open == 1) {
        /* close database handle */
        db_close_database(Driver);
        db_shutdown_driver(Driver);
    }

    /* close SVG-file */
    fclose(fpsvg);

    G_done_msg(" ");

    exit(EXIT_SUCCESS);
}