Beispiel #1
0
/*!
   \brief Extensive tests for correct topology

   - lines or boundaries of zero length
   - intersecting boundaries, ie. overlapping areas
   - areas without centroids that are not isles

   \param Map vector map
   \param[out] Err vector map where errors will be written or NULL

   \return 1 on success
   \return 0 on error
 */
int Vect_topo_check(struct Map_info *Map, struct Map_info *Err)
{
    int line, nlines;
    int nerrors, n_zero_lines, n_zero_boundaries;
    struct line_pnts *Points;
    struct line_cats *Cats;

    /* rebuild topology if needed */
    if (Vect_get_built(Map) != GV_BUILD_ALL) {
	Vect_build_partial(Map, GV_BUILD_NONE);
	Vect_build(Map);
    }

    G_message(_("Checking for topological errors..."));

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

    /* lines or boundaries of zero length */
    n_zero_lines = n_zero_boundaries = 0;
    nlines = Vect_get_num_lines(Map);
    for (line = 1; line <= nlines; line++) {
	int type;

	if (!Vect_line_alive(Map, line))
	    continue;
	    
	type = Vect_get_line_type(Map, line);

	if (type & GV_LINES) {
	    double len;
	    
	    Vect_read_line(Map, Points, Cats, line);
	    len = Vect_line_length(Points);
	    
	    if (len == 0) {
		if (type & GV_LINE)
		    n_zero_lines++;
		else if (type & GV_BOUNDARY)
		    n_zero_boundaries++;
		    
		if (Err)
		    Vect_write_line(Err, type, Points, Cats);
	    }
	}
    }
    
    if (n_zero_lines)
	G_warning(_("Number of lines of length zero: %d"), n_zero_lines);
    if (n_zero_boundaries)
	G_warning(_("Number of boundaries of length zero: %d"), n_zero_boundaries);

    /* remaining checks are for areas only */
    if (Vect_get_num_primitives(Map, GV_BOUNDARY) == 0)
	return 1;

    /* intersecting boundaries -> overlapping areas */
    nerrors = Vect_check_line_breaks(Map, GV_BOUNDARY, Err);
    if (nerrors)
	G_warning(_("Number of boundary intersections: %d"), nerrors);

    /* areas without centroids that are not isles
     * only makes sense if all boundaries are correct */
    nerrors = 0;
    for (line = 1; line <= nlines; line++) {
	int type;
	
	if (!Vect_line_alive(Map, line))
	    continue;
	    
	type = Vect_get_line_type(Map, line);

	if (type == GV_BOUNDARY) {
	    struct P_topo_b *topo = (struct P_topo_b *)Map->plus.Line[line]->topo;

	    if (topo->left == 0 || topo->right == 0) {
		G_debug(3, "line = %d left = %d right = %d", line, 
			topo->left, topo->right);
		nerrors++;
	    }
	}
    }
    if (nerrors)
	G_warning(_("Skipping further checks because of incorrect boundaries"));
    else {
	int i, area, left, right, neighbour;
	int nareas = Vect_get_num_areas(Map);
	struct ilist *List = Vect_new_list();

	nerrors = 0;
	for (area = 1; area <= nareas; area++) {
	    if (!Vect_area_alive(Map, area))
		continue;
	    line = Vect_get_area_centroid(Map, area);
	    if (line != 0)
		continue;   /* has centroid */

	    Vect_get_area_boundaries(Map, area, List);
	    for (i = 0; i < List->n_values; i++) {
		line = List->value[i];
		Vect_get_line_areas(Map, abs(line), &left, &right);
		if (line > 0)
		    neighbour = left;
		else
		    neighbour = right;
		    
		if (neighbour < 0) {
		    neighbour = Vect_get_isle_area(Map, abs(neighbour));
		    if (!neighbour) {
			/* borders outer void */
			nerrors++;
			if (Err) {
			    Vect_read_line(Map, Points, Cats, abs(line));
			    Vect_write_line(Err, GV_BOUNDARY, Points, Cats);
			}
		    }
		    /* else neighbour is > 0, check below */
		}
		if (neighbour > 0) {
		    if (Vect_get_area_centroid(Map, neighbour) == 0) {
			/* neighbouring area does not have a centroid either */
			nerrors++;
			if (Err) {
			    Vect_read_line(Map, Points, Cats, abs(line));
			    Vect_write_line(Err, GV_BOUNDARY, Points, Cats);
			}
		    }
		}
	    }
	}
	Vect_destroy_list(List);

	if (nerrors)
	    G_warning(_("Number of redundant holes: %d"), 
	              nerrors);
    }

    /* what else ? */

    Vect_destroy_line_struct(Points);
    Vect_destroy_cats_struct(Cats);

    return 1;
}
Beispiel #2
0
int display_label(struct Map_info *Map, int type,
		  struct cat_list *Clist, LATTR *lattr, int chcat)
{
    int ltype;
    struct line_pnts *Points;
    struct line_cats *Cats;
    int ogr_centroids;

    const struct Format_info *finfo;
    
    Points = Vect_new_line_struct();
    Cats = Vect_new_cats_struct();

    Vect_rewind(Map);

    ogr_centroids = FALSE;
    finfo = Vect_get_finfo(Map);
    if (Vect_maptype(Map) == GV_FORMAT_OGR ||
	(Vect_maptype(Map) == GV_FORMAT_POSTGIS &&
         finfo->pg.toposchema_name == NULL)) {
	if (Vect_level(Map) < 2)
	    G_warning(_("Topology level required for drawing centroids "
			"for OGR layers"));
	else if (Vect_get_num_primitives(Map, GV_CENTROID) > 0 &&
		 type & GV_CENTROID)
	    /* label centroids from topo, don't label boundaries */
	    ogr_centroids = TRUE;
    }
    
    while (TRUE) {
	ltype = Vect_read_next_line(Map, Points, Cats);
	if (ltype == -1)
	    G_fatal_error(_("Unable to read vector map"));
	else if (ltype == -2) /* EOF */
	    break;
	
        if (!(type & ltype) && !((type & GV_AREA) && (ltype & GV_CENTROID)))
	    continue;		/* used for both lines and labels */
	
	if (ogr_centroids && ltype == GV_BOUNDARY)
	    /* do not label boundaries */
	    continue;

	process_line(ltype, Points, Cats, lattr, chcat, Clist);
    }

    if (ogr_centroids) {
	/* show label for centroids stored in topo (for OGR layers
	   only) */
	int line, nlines;
	struct bound_box box;
	struct boxlist *list;
	
	list = Vect_new_boxlist(FALSE); /* bboxes not needed */
	Vect_get_constraint_box(Map, &box);
	nlines = Vect_select_lines_by_box(Map, &box, GV_CENTROID, list);
	G_debug(3, "ncentroids (ogr) = %d", nlines);
	
	for (line = 0; line < nlines; line++) {
	    ltype = Vect_read_line(Map, Points, Cats, list->id[line]);
	    process_line(ltype, Points, Cats, lattr, chcat, Clist);
	}
	Vect_destroy_boxlist(list);
    }

    Vect_destroy_line_struct(Points);
    Vect_destroy_cats_struct(Cats);

    return 0;
}
Beispiel #3
0
int main(int argc, char *argv[])
{
    int i, j, nlines, type, field, cat;
    int fd;

    /* struct Categories RCats; *//* TODO */
    struct Cell_head window;
    RASTER_MAP_TYPE out_type;
    CELL *cell;
    DCELL *dcell;
    double drow, dcol;
    char buf[2000];
    struct Option *vect_opt, *rast_opt, *field_opt, *col_opt, *where_opt;
    int Cache_size;
    struct order *cache;
    int cur_row;
    struct GModule *module;

    struct Map_info Map;
    struct line_pnts *Points;
    struct line_cats *Cats;
    int point;
    int point_cnt;		/* number of points in cache */
    int outside_cnt;		/* points outside region */
    int nocat_cnt;		/* points inside region but without category */
    int dupl_cnt;		/* duplicate categories */
    struct bound_box box;

    int *catexst, *cex;
    struct field_info *Fi;
    dbString stmt;
    dbDriver *driver;
    int select, norec_cnt, update_cnt, upderr_cnt, col_type;

    G_gisinit(argv[0]);

    module = G_define_module();
    G_add_keyword(_("vector"));
    G_add_keyword(_("raster"));
    G_add_keyword(_("position"));
    G_add_keyword(_("querying"));
    G_add_keyword(_("attribute table"));
    module->description =
	_("Uploads raster values at positions of vector points to the table.");

    vect_opt = G_define_standard_option(G_OPT_V_INPUT);
    vect_opt->key = "vector";
    vect_opt->description =
	_("Name of input vector points map for which to edit attribute table");

    rast_opt = G_define_standard_option(G_OPT_R_INPUT);
    rast_opt->key = "raster";
    rast_opt->description = _("Name of existing raster map to be queried");

    field_opt = G_define_standard_option(G_OPT_V_FIELD);

    col_opt = G_define_option();
    col_opt->key = "column";
    col_opt->type = TYPE_STRING;
    col_opt->required = YES;
    col_opt->description =
	_("Column name (will be updated by raster values)");

    where_opt = G_define_standard_option(G_OPT_DB_WHERE);

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


    field = atoi(field_opt->answer);

    db_init_string(&stmt);
    Points = Vect_new_line_struct();
    Cats = Vect_new_cats_struct();

    G_get_window(&window);
    Vect_region_box(&window, &box);	/* T and B set to +/- PORT_DOUBLE_MAX */

    /* Open vector */
    Vect_set_open_level(2);
    Vect_open_old(&Map, vect_opt->answer, "");

    Fi = Vect_get_field(&Map, field);
    if (Fi == NULL)
	G_fatal_error(_("Database connection not defined for layer %d"),
		      field);

    /* Open driver */
    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);
    }

    /* Open raster */
    fd = Rast_open_old(rast_opt->answer, "");

    out_type = Rast_get_map_type(fd);

    /* TODO: Later possibly category labels */
    /* 
       if ( Rast_read_cats (name, "", &RCats) < 0 )
       G_fatal_error ( "Cannot read category file");
     */

    /* Check column type */
    col_type = db_column_Ctype(driver, Fi->table, col_opt->answer);

    if (col_type == -1)
	G_fatal_error(_("Column <%s> not found"), col_opt->answer);

    if (col_type != DB_C_TYPE_INT && col_type != DB_C_TYPE_DOUBLE)
	G_fatal_error(_("Column type not supported"));

    if (out_type == CELL_TYPE && col_type == DB_C_TYPE_DOUBLE)
	G_warning(_("Raster type is integer and column type is float"));

    if (out_type != CELL_TYPE && col_type == DB_C_TYPE_INT)
	G_warning(_("Raster type is float and column type is integer, some data lost!!"));

    /* Read vector points to cache */
    Cache_size = Vect_get_num_primitives(&Map, GV_POINT);
    /* Note: Some space may be wasted (outside region or no category) */

    cache = (struct order *)G_calloc(Cache_size, sizeof(struct order));

    point_cnt = outside_cnt = nocat_cnt = 0;

    nlines = Vect_get_num_lines(&Map);

    G_debug(1, "Reading %d vector features fom map", nlines);

    for (i = 1; i <= nlines; i++) {
	type = Vect_read_line(&Map, Points, Cats, i);
	G_debug(4, "line = %d type = %d", i, type);

	/* check type */
	if (!(type & GV_POINT))
	    continue;		/* Points only */

	/* check region */
	if (!Vect_point_in_box(Points->x[0], Points->y[0], 0.0, &box)) {
	    outside_cnt++;
	    continue;
	}

	Vect_cat_get(Cats, field, &cat);
	if (cat < 0) {		/* no category of given field */
	    nocat_cnt++;
	    continue;
	}

	G_debug(4, "    cat = %d", cat);

	/* Add point to cache */
	drow = Rast_northing_to_row(Points->y[0], &window);
	dcol = Rast_easting_to_col(Points->x[0], &window);

	/* a special case.
	 *   if north falls at southern edge, or east falls on eastern edge,
	 *   the point will appear outside the window.
	 *   So, for these edges, bring the point inside the window
	 */
	if (drow == window.rows)
	    drow--;
	if (dcol == window.cols)
	    dcol--;

	cache[point_cnt].row = (int)drow;
	cache[point_cnt].col = (int)dcol;
	cache[point_cnt].cat = cat;
	cache[point_cnt].count = 1;
	point_cnt++;
    }

    Vect_set_db_updated(&Map);
    Vect_hist_command(&Map);
    Vect_close(&Map);

    G_debug(1, "Read %d vector points", point_cnt);
    /* Cache may contain duplicate categories, sort by cat, find and remove duplicates 
     * and recalc count and decrease point_cnt  */
    qsort(cache, point_cnt, sizeof(struct order), by_cat);

    G_debug(1, "Points are sorted, starting duplicate removal loop");

    for (i = 0, j = 1; j < point_cnt; j++)
	if (cache[i].cat != cache[j].cat)
	    cache[++i] = cache[j];
	else
	    cache[i].count++;
    point_cnt = i + 1;

    G_debug(1, "%d vector points left after removal of duplicates",
	    point_cnt);

    /* Report number of points not used */
    if (outside_cnt)
	G_warning(_("%d points outside current region were skipped"),
		  outside_cnt);

    if (nocat_cnt)
	G_warning(_("%d points without category were skipped"), nocat_cnt);

    /* Sort cache by current region row */
    qsort(cache, point_cnt, sizeof(struct order), by_row);

    /* Allocate space for raster row */
    if (out_type == CELL_TYPE)
	cell = Rast_allocate_c_buf();
    else
	dcell = Rast_allocate_d_buf();

    /* Extract raster values from file and store in cache */
    G_debug(1, "Extracting raster values");

    cur_row = -1;

    for (point = 0; point < point_cnt; point++) {
	if (cache[point].count > 1)
	    continue;		/* duplicate cats */

	if (cur_row != cache[point].row) {
	    if (out_type == CELL_TYPE)
		Rast_get_c_row(fd, cell, cache[point].row);
	    else
		Rast_get_d_row(fd, dcell, cache[point].row);
	}
	cur_row = cache[point].row;

	if (out_type == CELL_TYPE) {
	    cache[point].value = cell[cache[point].col];
	}
	else {
	    cache[point].dvalue = dcell[cache[point].col];
	}
    }				/* point loop */

    /* Update table from cache */
    G_debug(1, "Updating db table");

    /* select existing categories to array (array is sorted) */
    select = db_select_int(driver, Fi->table, Fi->key, NULL, &catexst);

    db_begin_transaction(driver);

    norec_cnt = update_cnt = upderr_cnt = dupl_cnt = 0;

    for (point = 0; point < point_cnt; point++) {
	if (cache[point].count > 1) {
	    G_warning(_("More points (%d) of category %d, value set to 'NULL'"),
		      cache[point].count, cache[point].cat);
	    dupl_cnt++;
	}

	/* category exist in DB ? */
	cex =
	    (int *)bsearch((void *)&(cache[point].cat), catexst, select,
			   sizeof(int), srch_cat);
	if (cex == NULL) {	/* cat does not exist in DB */
	    norec_cnt++;
	    G_warning(_("No record for category %d in table <%s>"),
		      cache[point].cat, Fi->table);
	    continue;
	}

	sprintf(buf, "update %s set %s = ", Fi->table, col_opt->answer);

	db_set_string(&stmt, buf);

	if (out_type == CELL_TYPE) {
	    if (cache[point].count > 1 ||
		Rast_is_c_null_value(&cache[point].value)) {
		sprintf(buf, "NULL");
	    }
	    else {
		sprintf(buf, "%d ", cache[point].value);
	    }
	}
	else {			/* FCELL or DCELL */
	    if (cache[point].count > 1 ||
		Rast_is_d_null_value(&cache[point].dvalue)) {
		sprintf(buf, "NULL");
	    }
	    else {
		sprintf(buf, "%.10f", cache[point].dvalue);
	    }
	}
	db_append_string(&stmt, buf);

	sprintf(buf, " where %s = %d", Fi->key, cache[point].cat);
	db_append_string(&stmt, buf);
	/* user provides where condition: */
	if (where_opt->answer) {
	    sprintf(buf, " AND %s", where_opt->answer);
	    db_append_string(&stmt, buf);
	}
	G_debug(3, db_get_string(&stmt));

	/* Update table */
	if (db_execute_immediate(driver, &stmt) == DB_OK) {
	    update_cnt++;
	}
	else {
	    upderr_cnt++;
	}
    }

    G_debug(1, "Committing DB transaction");
    db_commit_transaction(driver);
    G_free(catexst);
    db_close_database_shutdown_driver(driver);
    db_free_string(&stmt);

    /* Report */
    G_message(_("%d categories loaded from table"), select);
    G_message(_("%d categories loaded from vector"), point_cnt);
    G_message(_("%d categories from vector missing in table"), norec_cnt);
    G_message(_("%d duplicate categories in vector"), dupl_cnt);
    if (!where_opt->answer)
	G_message(_("%d records updated"), update_cnt);
    G_message(_("%d update errors"), upderr_cnt);

    exit(EXIT_SUCCESS);
}
Beispiel #4
0
int main(int argc, char *argv[])
{
    struct Option *vector_opt, *seed_opt, *flowlines_opt, *flowacc_opt, *sampled_opt,
	*scalar_opt, *unit_opt, *step_opt, *limit_opt, *skip_opt, *dir_opt,
	*error_opt;
    struct Flag *table_fl;
    struct GModule *module;
    RASTER3D_Region region;
    RASTER3D_Map *flowacc, *sampled;
    struct Integration integration;
    struct Seed seed;
    struct Gradient_info gradient_info;
    struct Map_info seed_Map;
    struct line_pnts *seed_points;
    struct line_cats *seed_cats;
    struct Map_info fl_map;
    struct line_cats *fl_cats;	/* for flowlines */
    struct line_pnts *fl_points;	/* for flowlines */
    struct field_info *finfo;
    dbDriver *driver;
    int cat;			/* cat of flowlines */
    int if_table;
    int i, r, c, d;
    char *desc;
    int n_seeds, seed_count, ltype;
    int skip[3];

    G_gisinit(argv[0]);
    module = G_define_module();
    G_add_keyword(_("raster3d"));
    G_add_keyword(_("hydrology"));
    G_add_keyword(_("voxel"));
    module->description =
	_("Computes 3D flow lines and 3D flow accumulation.");


    scalar_opt = G_define_standard_option(G_OPT_R3_INPUT);
    scalar_opt->required = NO;
    scalar_opt->guisection = _("Input");

    vector_opt = G_define_standard_option(G_OPT_R3_INPUTS);
    vector_opt->key = "vector_field";
    vector_opt->required = NO;
    vector_opt->description = _("Names of three 3D raster maps describing "
				"x, y, z components of vector field");
    vector_opt->guisection = _("Input");

    seed_opt = G_define_standard_option(G_OPT_V_INPUT);
    seed_opt->required = NO;
    seed_opt->key = "seed_points";
    seed_opt->description = _("If no map is provided, "
			      "flow lines are generated "
			      "from each cell of the input 3D raster");
    seed_opt->label = _("Name of vector map with points "
			"from which flow lines are generated");
    seed_opt->guisection = _("Input");

    flowlines_opt = G_define_standard_option(G_OPT_V_OUTPUT);
    flowlines_opt->key = "flowline";
    flowlines_opt->required = NO;
    flowlines_opt->description = _("Name for vector map of flow lines");
    flowlines_opt->guisection = _("Output");

    flowacc_opt = G_define_standard_option(G_OPT_R3_OUTPUT);
    flowacc_opt->key = "flowaccumulation";
    flowacc_opt->required = NO;
    flowacc_opt->description =
	_("Name for output flowaccumulation 3D raster");
    flowacc_opt->guisection = _("Output");

    sampled_opt = G_define_standard_option(G_OPT_R3_INPUT);
    sampled_opt->key = "sampled";
    sampled_opt->required = NO;
    sampled_opt->label =
            _("Name for 3D raster sampled by flowlines");
    sampled_opt->description =
            _("Values of this 3D raster will be stored "
              "as attributes of flowlines segments");

    unit_opt = G_define_option();
    unit_opt->key = "unit";
    unit_opt->type = TYPE_STRING;
    unit_opt->required = NO;
    unit_opt->answer = "cell";
    unit_opt->options = "time,length,cell";
    desc = NULL;
    G_asprintf(&desc,
	       "time;%s;"
	       "length;%s;"
	       "cell;%s",
	       _("elapsed time"),
	       _("length in map units"), _("length in cells (voxels)"));
    unit_opt->descriptions = desc;
    unit_opt->label = _("Unit of integration step");
    unit_opt->description = _("Default unit is cell");
    unit_opt->guisection = _("Integration");

    step_opt = G_define_option();
    step_opt->key = "step";
    step_opt->type = TYPE_DOUBLE;
    step_opt->required = NO;
    step_opt->answer = "0.25";
    step_opt->label = _("Integration step in selected unit");
    step_opt->description = _("Default step is 0.25 cell");
    step_opt->guisection = _("Integration");

    limit_opt = G_define_option();
    limit_opt->key = "limit";
    limit_opt->type = TYPE_INTEGER;
    limit_opt->required = NO;
    limit_opt->answer = "2000";
    limit_opt->description = _("Maximum number of steps");
    limit_opt->guisection = _("Integration");

    error_opt = G_define_option();
    error_opt->key = "max_error";
    error_opt->type = TYPE_DOUBLE;
    error_opt->required = NO;
    error_opt->answer = "1e-5";
    error_opt->label = _("Maximum error of integration");
    error_opt->description = _("Influences step, increase maximum error "
			       "to allow bigger steps");
    error_opt->guisection = _("Integration");

    skip_opt = G_define_option();
    skip_opt->key = "skip";
    skip_opt->type = TYPE_INTEGER;
    skip_opt->required = NO;
    skip_opt->multiple = YES;
    skip_opt->description =
	_("Number of cells between flow lines in x, y and z direction");

    dir_opt = G_define_option();
    dir_opt->key = "direction";
    dir_opt->type = TYPE_STRING;
    dir_opt->required = NO;
    dir_opt->multiple = NO;
    dir_opt->options = "up,down,both";
    dir_opt->answer = "down";
    dir_opt->description = _("Compute flowlines upstream, "
			     "downstream or in both direction.");

    table_fl = G_define_flag();
    table_fl->key = 'a';
    table_fl->description = _("Create and fill attribute table");

    G_option_required(scalar_opt, vector_opt, NULL);
    G_option_exclusive(scalar_opt, vector_opt, NULL);
    G_option_required(flowlines_opt, flowacc_opt, NULL);
    G_option_requires(seed_opt, flowlines_opt, NULL);
    G_option_requires(table_fl, flowlines_opt, NULL);
    G_option_requires(sampled_opt, table_fl, NULL);

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

    driver = NULL;
    finfo = NULL;

    if_table = table_fl->answer ? TRUE : FALSE;

    check_vector_input_maps(vector_opt, seed_opt);

    Rast3d_init_defaults();
    Rast3d_get_window(&region);

    /* set up integration variables */
    if (step_opt->answer) {
	integration.step = atof(step_opt->answer);
	integration.unit = unit_opt->answer;
    }
    else {
	integration.unit = "cell";
	integration.step = 0.25;
    }
    integration.max_error = atof(error_opt->answer);
    integration.max_step = 5 * integration.step;
    integration.min_step = integration.step / 5;
    integration.limit = atof(limit_opt->answer);
    if (strcmp(dir_opt->answer, "up") == 0)
	integration.direction_type = FLOWDIR_UP;
    else if (strcmp(dir_opt->answer, "down") == 0)
	integration.direction_type = FLOWDIR_DOWN;
    else
	integration.direction_type = FLOWDIR_BOTH;


    /* cell size is the diagonal */
    integration.cell_size = sqrt(region.ns_res * region.ns_res +
				 region.ew_res * region.ew_res +
				 region.tb_res * region.tb_res);

    /* set default skip if needed */
    if (skip_opt->answers) {
	for (i = 0; i < 3; i++) {
	    if (skip_opt->answers[i] != NULL) {
		skip[i] = atoi(skip_opt->answers[i]);
	    }
	    else {
		G_fatal_error(_("Please provide 3 integer values for skip option."));
	    }
	}
    }
    else {
	skip[0] = fmax(1, region.cols / 10);
	skip[1] = fmax(1, region.rows / 10);
	skip[2] = fmax(1, region.depths / 10);

    }

    /* open raster 3D maps of velocity components */
    gradient_info.initialized = FALSE;
    load_input_raster3d_maps(scalar_opt, vector_opt, &gradient_info, &region);


    /* open new 3D raster map of flowacumulation */
    if (flowacc_opt->answer) {
	flowacc = Rast3d_open_new_opt_tile_size(flowacc_opt->answer,
						RASTER3D_USE_CACHE_DEFAULT,
						&region, FCELL_TYPE, 32);


	if (!flowacc)
	    Rast3d_fatal_error(_("Unable to open 3D raster map <%s>"),
			       flowacc_opt->answer);
	init_flowaccum(&region, flowacc);
    }

    /* open 3D raster map used for sampling */
    if (sampled_opt->answer) {
	sampled = Rast3d_open_cell_old(sampled_opt->answer,
				       G_find_raster3d(sampled_opt->answer, ""),
				       &region, RASTER3D_TILE_SAME_AS_FILE,
				       RASTER3D_USE_CACHE_DEFAULT);
	if (!sampled)
	    Rast3d_fatal_error(_("Unable to open 3D raster map <%s>"),
			       sampled_opt->answer);
    }
    else
	sampled = NULL;

    /* open new vector map of flowlines */
    if (flowlines_opt->answer) {
	fl_cats = Vect_new_cats_struct();
	fl_points = Vect_new_line_struct();
	if (Vect_open_new(&fl_map, flowlines_opt->answer, TRUE) < 0)
	    G_fatal_error(_("Unable to create vector map <%s>"),
			  flowlines_opt->answer);

	Vect_hist_command(&fl_map);

	if (if_table) {
	    create_table(&fl_map, &finfo, &driver,
			 gradient_info.compute_gradient, sampled ? 1 : 0);
	}
    }

    n_seeds = 0;
    /* open vector map of seeds */
    if (seed_opt->answer) {
	if (Vect_open_old2(&seed_Map, seed_opt->answer, "", "1") < 0)
	    G_fatal_error(_("Unable to open vector map <%s>"),
			  seed_opt->answer);
	if (!Vect_is_3d(&seed_Map))
	    G_fatal_error(_("Vector map <%s> is not 3D"), seed_opt->answer);

	n_seeds = Vect_get_num_primitives(&seed_Map, GV_POINT);
    }
    if (flowacc_opt->answer || (!seed_opt->answer && flowlines_opt->answer)) {
	if (flowacc_opt->answer)
	    n_seeds += region.cols * region.rows * region.depths;
	else {
	    n_seeds += ceil(region.cols / (double)skip[0]) *
		ceil(region.rows / (double)skip[1]) *
		ceil(region.depths / (double)skip[2]);
	}
    }
    G_debug(1, "Number of seeds is %d", n_seeds);

    seed_count = 0;
    cat = 1;
    if (seed_opt->answer) {

	seed_points = Vect_new_line_struct();
	seed_cats = Vect_new_cats_struct();

	/* compute flowlines from vector seed map */
	while (TRUE) {
	    ltype = Vect_read_next_line(&seed_Map, seed_points, seed_cats);
	    if (ltype == -1) {
		Vect_close(&seed_Map);
		G_fatal_error(_("Error during reading seed vector map"));
	    }
	    else if (ltype == -2) {
		break;
	    }
	    else if (ltype == GV_POINT) {
		seed.x = seed_points->x[0];
		seed.y = seed_points->y[0];
		seed.z = seed_points->z[0];
		seed.flowline = TRUE;
		seed.flowaccum = FALSE;
	    }
	    G_percent(seed_count, n_seeds, 1);
	    if (integration.direction_type == FLOWDIR_UP ||
		integration.direction_type == FLOWDIR_BOTH) {
		integration.actual_direction = FLOWDIR_UP;
		compute_flowline(&region, &seed, &gradient_info, flowacc, sampled,
				 &integration, &fl_map, fl_cats, fl_points,
				 &cat, if_table, finfo, driver);
	    }
	    if (integration.direction_type == FLOWDIR_DOWN ||
		integration.direction_type == FLOWDIR_BOTH) {
		integration.actual_direction = FLOWDIR_DOWN;
		compute_flowline(&region, &seed, &gradient_info, flowacc, sampled,
				 &integration, &fl_map, fl_cats, fl_points,
				 &cat, if_table, finfo, driver);
	    }
	    seed_count++;
	}

	Vect_destroy_line_struct(seed_points);
	Vect_destroy_cats_struct(seed_cats);
	Vect_close(&seed_Map);
    }
    if (flowacc_opt->answer || (!seed_opt->answer && flowlines_opt->answer)) {
	/* compute flowlines from points on grid */
	for (r = region.rows; r > 0; r--) {
	    for (c = 0; c < region.cols; c++) {
		for (d = 0; d < region.depths; d++) {
		    seed.x =
			region.west + c * region.ew_res + region.ew_res / 2;
		    seed.y =
			region.south + r * region.ns_res - region.ns_res / 2;
		    seed.z =
			region.bottom + d * region.tb_res + region.tb_res / 2;
		    seed.flowline = FALSE;
		    seed.flowaccum = FALSE;
		    if (flowacc_opt->answer)
			seed.flowaccum = TRUE;

		    if (flowlines_opt->answer && !seed_opt->answer &&
		       (c % skip[0] == 0) && (r % skip[1] == 0) && (d % skip[2] == 0))
			seed.flowline = TRUE;

		    if (seed.flowaccum || seed.flowline) {
			G_percent(seed_count, n_seeds, 1);

			if (integration.direction_type == FLOWDIR_UP ||
			    integration.direction_type == FLOWDIR_BOTH) {
			    integration.actual_direction = FLOWDIR_UP;
			    compute_flowline(&region, &seed, &gradient_info,
					     flowacc, sampled, &integration, &fl_map,
					     fl_cats, fl_points, &cat,
					     if_table, finfo, driver);
			}
			if (integration.direction_type == FLOWDIR_DOWN ||
			    integration.direction_type == FLOWDIR_BOTH) {
			    integration.actual_direction = FLOWDIR_DOWN;
			    compute_flowline(&region, &seed, &gradient_info,
					     flowacc, sampled, &integration, &fl_map,
					     fl_cats, fl_points, &cat,
					     if_table, finfo, driver);
			}
			seed_count++;
		    }
		}
	    }
	}
    }
    G_percent(1, 1, 1);
    if (flowlines_opt->answer) {
	if (if_table) {
	    db_commit_transaction(driver);
	    db_close_database_shutdown_driver(driver);
	}
	Vect_destroy_line_struct(fl_points);
	Vect_destroy_cats_struct(fl_cats);
	Vect_build(&fl_map);
	Vect_close(&fl_map);
    }

    if (flowacc_opt->answer)
	Rast3d_close(flowacc);


    return EXIT_SUCCESS;
}
Beispiel #5
0
int main(int argc, char *argv[])
{
    struct GModule *module;
    struct _param {
        struct Option *dsn, *out, *layer, *spat, *where,
                   *min_area;
        struct Option *snap, *type, *outloc, *cnames;
    } param;
    struct _flag {
        struct Flag *list, *tlist, *no_clean, *z, *notab,
                   *region;
        struct Flag *over, *extend, *formats, *tolower, *no_import;
    } flag;

    int i, j, layer, arg_s_num, nogeom, ncnames;
    float xmin, ymin, xmax, ymax;
    int ncols = 0, type;
    double min_area, snap;
    char buf[2000], namebuf[2000], tempvect[GNAME_MAX];
    char *separator;

    struct Key_Value *loc_proj_info, *loc_proj_units;
    struct Key_Value *proj_info, *proj_units;
    struct Cell_head cellhd, loc_wind, cur_wind;
    char error_msg[8192];

    /* Vector */
    struct Map_info Map, Tmp, *Out;
    int cat;

    /* Attributes */
    struct field_info *Fi;
    dbDriver *driver;
    dbString sql, strval;
    int dim, with_z;

    /* OGR */
    OGRDataSourceH Ogr_ds;
    OGRLayerH Ogr_layer;
    OGRFieldDefnH Ogr_field;
    char *Ogr_fieldname;
    OGRFieldType Ogr_ftype;
    OGRFeatureH Ogr_feature;
    OGRFeatureDefnH Ogr_featuredefn;
    OGRGeometryH Ogr_geometry, Ogr_oRing, poSpatialFilter;
    OGRSpatialReferenceH Ogr_projection;
    OGREnvelope oExt;
    OGRwkbGeometryType Ogr_geom_type;

    int OFTIntegerListlength;

    char *output;
    char **layer_names;		/* names of layers to be imported */
    int *layers;		/* layer indexes */
    int nlayers;		/* number of layers to import */
    char **available_layer_names;	/* names of layers to be imported */
    int navailable_layers;
    int layer_id;
    unsigned int n_features, feature_count;
    int overwrite;
    double area_size;
    int use_tmp_vect;

    xmin = ymin = xmax = ymax = 0.0;
    loc_proj_info = loc_proj_units = NULL;
    Ogr_ds = Ogr_oRing = poSpatialFilter = NULL;
    OFTIntegerListlength = 40;	/* hack due to limitation in OGR */
    area_size = 0.0;
    use_tmp_vect = FALSE;

    G_gisinit(argv[0]);

    module = G_define_module();
    G_add_keyword(_("vector"));
    G_add_keyword(_("import"));
    module->description = _("Converts vector data into a GRASS vector map using OGR library.");

    param.dsn = G_define_option();
    param.dsn->key = "dsn";
    param.dsn->type = TYPE_STRING;
    param.dsn->required =YES;
    param.dsn->label = _("OGR datasource name");
    param.dsn->description = _("Examples:\n"
                               "\t\tESRI Shapefile: directory containing shapefiles\n"
                               "\t\tMapInfo File: directory containing mapinfo files");

    param.layer = G_define_option();
    param.layer->key = "layer";
    param.layer->type = TYPE_STRING;
    param.layer->required = NO;
    param.layer->multiple = YES;
    param.layer->label =
        _("OGR layer name. If not given, all available layers are imported");
    param.layer->description =
        _("Examples:\n" "\t\tESRI Shapefile: shapefile name\n"
          "\t\tMapInfo File: mapinfo file name");
    param.layer->guisection = _("Selection");

    param.out = G_define_standard_option(G_OPT_V_OUTPUT);
    param.out->required = NO;
    param.out->guisection = _("Output");

    param.spat = G_define_option();
    param.spat->key = "spatial";
    param.spat->type = TYPE_DOUBLE;
    param.spat->multiple = YES;
    param.spat->required = NO;
    param.spat->key_desc = "xmin,ymin,xmax,ymax";
    param.spat->label = _("Import subregion only");
    param.spat->guisection = _("Selection");
    param.spat->description =
        _("Format: xmin,ymin,xmax,ymax - usually W,S,E,N");

    param.where = G_define_standard_option(G_OPT_DB_WHERE);
    param.where->guisection = _("Selection");

    param.min_area = G_define_option();
    param.min_area->key = "min_area";
    param.min_area->type = TYPE_DOUBLE;
    param.min_area->required = NO;
    param.min_area->answer = "0.0001";
    param.min_area->label =
        _("Minimum size of area to be imported (square units)");
    param.min_area->guisection = _("Selection");
    param.min_area->description = _("Smaller areas and "
                                    "islands are ignored. Should be greater than snap^2");

    param.type = G_define_standard_option(G_OPT_V_TYPE);
    param.type->options = "point,line,boundary,centroid";
    param.type->answer = "";
    param.type->description = _("Optionally change default input type");
    param.type->descriptions =
        _("point;import area centroids as points;"
          "line;import area boundaries as lines;"
          "boundary;import lines as area boundaries;"
          "centroid;import points as centroids");
    param.type->guisection = _("Selection");

    param.snap = G_define_option();
    param.snap->key = "snap";
    param.snap->type = TYPE_DOUBLE;
    param.snap->required = NO;
    param.snap->answer = "-1";
    param.snap->label = _("Snapping threshold for boundaries");
    param.snap->description = _("'-1' for no snap");

    param.outloc = G_define_option();
    param.outloc->key = "location";
    param.outloc->type = TYPE_STRING;
    param.outloc->required = NO;
    param.outloc->description = _("Name for new location to create");
    param.outloc->key_desc = "name";

    param.cnames = G_define_option();
    param.cnames->key = "cnames";
    param.cnames->type = TYPE_STRING;
    param.cnames->required = NO;
    param.cnames->multiple = YES;
    param.cnames->description =
        _("List of column names to be used instead of original names, "
          "first is used for category column");
    param.cnames->guisection = _("Attributes");

    flag.list = G_define_flag();
    flag.list->key = 'l';
    flag.list->description = _("List available OGR layers in data source and exit");
    flag.list->suppress_required = YES;
    flag.list->guisection = _("Print");

    flag.tlist = G_define_flag();
    flag.tlist->key = 'a';
    flag.tlist->description = _("List available OGR layers including feature types "
                                "in data source and exit");
    flag.tlist->suppress_required = YES;
    flag.tlist->guisection = _("Print");

    flag.formats = G_define_flag();
    flag.formats->key = 'f';
    flag.formats->description = _("List supported formats and exit");
    flag.formats->suppress_required = YES;
    flag.formats->guisection = _("Print");

    /* if using -c, you lose topological information ! */
    flag.no_clean = G_define_flag();
    flag.no_clean->key = 'c';
    flag.no_clean->description = _("Do not clean polygons (not recommended)");
    flag.no_clean->guisection = _("Output");

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

    flag.notab = G_define_flag();
    flag.notab->key = 't';
    flag.notab->description = _("Do not create attribute table");
    flag.notab->guisection = _("Attributes");

    flag.over = G_define_flag();
    flag.over->key = 'o';
    flag.over->description =
        _("Override dataset projection (use location's projection)");

    flag.region = G_define_flag();
    flag.region->key = 'r';
    flag.region->guisection = _("Selection");
    flag.region->description = _("Limit import to the current region");

    flag.extend = G_define_flag();
    flag.extend->key = 'e';
    flag.extend->description =
        _("Extend location extents based on new dataset");

    flag.tolower = G_define_flag();
    flag.tolower->key = 'w';
    flag.tolower->description =
        _("Change column names to lowercase characters");
    flag.tolower->guisection = _("Attributes");

    flag.no_import = G_define_flag();
    flag.no_import->key = 'i';
    flag.no_import->description =
        _("Create the location specified by the \"location\" parameter and exit."
          " Do not import the vector data.");

    /* The parser checks if the map already exists in current mapset, this is
     * wrong if location options is used, so we switch out the check and do it
     * in the module after the parser */
    overwrite = G_check_overwrite(argc, argv);

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

    G_begin_polygon_area_calculations();	/* Used in geom() */

    OGRRegisterAll();

    /* list supported formats */
    if (flag.formats->answer) {
        int iDriver;

        G_message(_("Available OGR Drivers:"));

        for (iDriver = 0; iDriver < OGRGetDriverCount(); iDriver++) {
            OGRSFDriverH poDriver = OGRGetDriver(iDriver);
            const char *pszRWFlag;

            if (OGR_Dr_TestCapability(poDriver, ODrCCreateDataSource))
                pszRWFlag = "rw";
            else
                pszRWFlag = "ro";

            fprintf(stdout, " %s (%s): %s\n",
                    OGR_Dr_GetName(poDriver),
                    pszRWFlag, OGR_Dr_GetName(poDriver));
        }
        exit(EXIT_SUCCESS);
    }

    if (param.dsn->answer == NULL) {
        G_fatal_error(_("Required parameter <%s> not set"), param.dsn->key);
    }

    min_area = atof(param.min_area->answer);
    snap = atof(param.snap->answer);
    type = Vect_option_to_types(param.type);

    ncnames = 0;
    if (param.cnames->answers) {
        i = 0;
        while (param.cnames->answers[i++]) {
            ncnames++;
        }
    }

    /* Open OGR DSN */
    Ogr_ds = NULL;
    if (strlen(param.dsn->answer) > 0)
        Ogr_ds = OGROpen(param.dsn->answer, FALSE, NULL);

    if (Ogr_ds == NULL)
        G_fatal_error(_("Unable to open data source <%s>"), param.dsn->answer);

    /* Make a list of available layers */
    navailable_layers = OGR_DS_GetLayerCount(Ogr_ds);
    available_layer_names =
        (char **)G_malloc(navailable_layers * sizeof(char *));

    if (flag.list->answer || flag.tlist->answer)
        G_message(_("Data source <%s> (format '%s') contains %d layers:"),
                  param.dsn->answer,
                  OGR_Dr_GetName(OGR_DS_GetDriver(Ogr_ds)), navailable_layers);
    for (i = 0; i < navailable_layers; i++) {
        Ogr_layer = OGR_DS_GetLayer(Ogr_ds, i);
        Ogr_featuredefn = OGR_L_GetLayerDefn(Ogr_layer);
        Ogr_geom_type = OGR_FD_GetGeomType(Ogr_featuredefn);

        available_layer_names[i] =
            G_store((char *)OGR_FD_GetName(Ogr_featuredefn));

        if (flag.tlist->answer)
            fprintf(stdout, "%s (%s)\n", available_layer_names[i],
                    OGRGeometryTypeToName(Ogr_geom_type));
        else if (flag.list->answer)
            fprintf(stdout, "%s\n", available_layer_names[i]);
    }
    if (flag.list->answer || flag.tlist->answer) {
        fflush(stdout);
        exit(EXIT_SUCCESS);
    }

    /* Make a list of layers to be imported */
    if (param.layer->answer) {	/* From option */
        nlayers = 0;
        while (param.layer->answers[nlayers])
            nlayers++;

        layer_names = (char **)G_malloc(nlayers * sizeof(char *));
        layers = (int *)G_malloc(nlayers * sizeof(int));

        for (i = 0; i < nlayers; i++) {
            layer_names[i] = G_store(param.layer->answers[i]);
            /* Find it in the source */
            layers[i] = -1;
            for (j = 0; j < navailable_layers; j++) {
                if (strcmp(available_layer_names[j], layer_names[i]) == 0) {
                    layers[i] = j;
                    break;
                }
            }
            if (layers[i] == -1)
                G_fatal_error(_("Layer <%s> not available"), layer_names[i]);
        }
    }
    else {			/* use list of all layers */
        nlayers = navailable_layers;
        layer_names = available_layer_names;
        layers = (int *)G_malloc(nlayers * sizeof(int));
        for (i = 0; i < nlayers; i++)
            layers[i] = i;
    }

    if (param.out->answer) {
        output = G_store(param.out->answer);
    }
    else {
        if (nlayers < 1)
            G_fatal_error(_("No OGR layers available"));
        output = G_store(layer_names[0]);
        G_message(_("All available OGR layers will be imported into vector map <%s>"), output);
    }

    if (!param.outloc->answer) {	/* Check if the map exists */
        if (G_find_vector2(output, G_mapset()) && !overwrite)
            G_fatal_error(_("Vector map <%s> already exists"),
                          output);
    }

    /* Get first imported layer to use for extents and projection check */
    Ogr_layer = OGR_DS_GetLayer(Ogr_ds, layers[0]);

    if (flag.region->answer) {
        if (param.spat->answer)
            G_fatal_error(_("Select either the current region flag or the spatial option, not both"));

        G_get_window(&cur_wind);
        xmin = cur_wind.west;
        xmax = cur_wind.east;
        ymin = cur_wind.south;
        ymax = cur_wind.north;
    }
    if (param.spat->answer) {
        /* See as reference: gdal/ogr/ogr_capi_test.c */

        /* cut out a piece of the map */
        /* order: xmin,ymin,xmax,ymax */
        arg_s_num = 0;
        i = 0;
        while (param.spat->answers[i]) {
            if (i == 0)
                xmin = atof(param.spat->answers[i]);
            if (i == 1)
                ymin = atof(param.spat->answers[i]);
            if (i == 2)
                xmax = atof(param.spat->answers[i]);
            if (i == 3)
                ymax = atof(param.spat->answers[i]);
            arg_s_num++;
            i++;
        }
        if (arg_s_num != 4)
            G_fatal_error(_("4 parameters required for 'spatial' parameter"));
    }
    if (param.spat->answer || flag.region->answer) {
        G_debug(2, "cut out with boundaries: xmin:%f ymin:%f xmax:%f ymax:%f",
                xmin, ymin, xmax, ymax);

        /* in theory this could be an irregular polygon */
        poSpatialFilter = OGR_G_CreateGeometry(wkbPolygon);
        Ogr_oRing = OGR_G_CreateGeometry(wkbLinearRing);
        OGR_G_AddPoint(Ogr_oRing, xmin, ymin, 0.0);
        OGR_G_AddPoint(Ogr_oRing, xmin, ymax, 0.0);
        OGR_G_AddPoint(Ogr_oRing, xmax, ymax, 0.0);
        OGR_G_AddPoint(Ogr_oRing, xmax, ymin, 0.0);
        OGR_G_AddPoint(Ogr_oRing, xmin, ymin, 0.0);
        OGR_G_AddGeometryDirectly(poSpatialFilter, Ogr_oRing);

        OGR_L_SetSpatialFilter(Ogr_layer, poSpatialFilter);
    }

    if (param.where->answer) {
        /* select by attribute */
        OGR_L_SetAttributeFilter(Ogr_layer, param.where->answer);
    }

    /* fetch boundaries */
    if ((OGR_L_GetExtent(Ogr_layer, &oExt, 1)) == OGRERR_NONE) {
        G_get_window(&cellhd);
        cellhd.north = oExt.MaxY;
        cellhd.south = oExt.MinY;
        cellhd.west = oExt.MinX;
        cellhd.east = oExt.MaxX;
        cellhd.rows = 20;	/* TODO - calculate useful values */
        cellhd.cols = 20;
        cellhd.ns_res = (cellhd.north - cellhd.south) / cellhd.rows;
        cellhd.ew_res = (cellhd.east - cellhd.west) / cellhd.cols;
    }
    else {
        cellhd.north = 1.;
        cellhd.south = 0.;
        cellhd.west = 0.;
        cellhd.east = 1.;
        cellhd.top = 1.;
        cellhd.bottom = 1.;
        cellhd.rows = 1;
        cellhd.rows3 = 1;
        cellhd.cols = 1;
        cellhd.cols3 = 1;
        cellhd.depths = 1;
        cellhd.ns_res = 1.;
        cellhd.ns_res3 = 1.;
        cellhd.ew_res = 1.;
        cellhd.ew_res3 = 1.;
        cellhd.tb_res = 1.;
    }

    /* suppress boundary splitting ? */
    if (flag.no_clean->answer) {
        split_distance = -1.;
    }
    else {
        split_distance = 0.;
        area_size =
            sqrt((cellhd.east - cellhd.west) * (cellhd.north - cellhd.south));
    }

    /* Fetch input map projection in GRASS form. */
    proj_info = NULL;
    proj_units = NULL;
    Ogr_projection = OGR_L_GetSpatialRef(Ogr_layer);	/* should not be freed later */

    /* Do we need to create a new location? */
    if (param.outloc->answer != NULL) {
        /* Convert projection information non-interactively as we can't
         * assume the user has a terminal open */
        if (GPJ_osr_to_grass(&cellhd, &proj_info,
                             &proj_units, Ogr_projection, 0) < 0) {
            G_fatal_error(_("Unable to convert input map projection to GRASS "
                            "format; cannot create new location."));
        }
        else {
            G_make_location(param.outloc->answer, &cellhd,
                            proj_info, proj_units, NULL);
            G_message(_("Location <%s> created"), param.outloc->answer);
        }

        /* If the i flag is set, clean up? and exit here */
        if(flag.no_import->answer)
        {
            exit(EXIT_SUCCESS);
        }
    }
    else {
        int err = 0;

        /* Projection only required for checking so convert non-interactively */
        if (GPJ_osr_to_grass(&cellhd, &proj_info,
                             &proj_units, Ogr_projection, 0) < 0)
            G_warning(_("Unable to convert input map projection information to "
                        "GRASS format for checking"));

        /* Does the projection of the current location match the dataset? */
        /* G_get_window seems to be unreliable if the location has been changed */
        G__get_window(&loc_wind, "", "DEFAULT_WIND", "PERMANENT");
        /* fetch LOCATION PROJ info */
        if (loc_wind.proj != PROJECTION_XY) {
            loc_proj_info = G_get_projinfo();
            loc_proj_units = G_get_projunits();
        }

        if (flag.over->answer) {
            cellhd.proj = loc_wind.proj;
            cellhd.zone = loc_wind.zone;
            G_message(_("Over-riding projection check"));
        }
        else if (loc_wind.proj != cellhd.proj
                 || (err =
                         G_compare_projections(loc_proj_info, loc_proj_units,
                                               proj_info, proj_units)) != TRUE) {
            int i_value;

            strcpy(error_msg,
                   _("Projection of dataset does not"
                     " appear to match current location.\n\n"));

            /* TODO: output this info sorted by key: */
            if (loc_wind.proj != cellhd.proj || err != -2) {
                if (loc_proj_info != NULL) {
                    strcat(error_msg, _("GRASS LOCATION PROJ_INFO is:\n"));
                    for (i_value = 0; i_value < loc_proj_info->nitems;
                            i_value++)
                        sprintf(error_msg + strlen(error_msg), "%s: %s\n",
                                loc_proj_info->key[i_value],
                                loc_proj_info->value[i_value]);
                    strcat(error_msg, "\n");
                }

                if (proj_info != NULL) {
                    strcat(error_msg, _("Import dataset PROJ_INFO is:\n"));
                    for (i_value = 0; i_value < proj_info->nitems; i_value++)
                        sprintf(error_msg + strlen(error_msg), "%s: %s\n",
                                proj_info->key[i_value],
                                proj_info->value[i_value]);
                }
                else {
                    strcat(error_msg, _("Import dataset PROJ_INFO is:\n"));
                    if (cellhd.proj == PROJECTION_XY)
                        sprintf(error_msg + strlen(error_msg),
                                "Dataset proj = %d (unreferenced/unknown)\n",
                                cellhd.proj);
                    else if (cellhd.proj == PROJECTION_LL)
                        sprintf(error_msg + strlen(error_msg),
                                "Dataset proj = %d (lat/long)\n",
                                cellhd.proj);
                    else if (cellhd.proj == PROJECTION_UTM)
                        sprintf(error_msg + strlen(error_msg),
                                "Dataset proj = %d (UTM), zone = %d\n",
                                cellhd.proj, cellhd.zone);
                    else if (cellhd.proj == PROJECTION_SP)
                        sprintf(error_msg + strlen(error_msg),
                                "Dataset proj = %d (State Plane), zone = %d\n",
                                cellhd.proj, cellhd.zone);
                    else
                        sprintf(error_msg + strlen(error_msg),
                                "Dataset proj = %d (unknown), zone = %d\n",
                                cellhd.proj, cellhd.zone);
                }
            }
            else {
                if (loc_proj_units != NULL) {
                    strcat(error_msg, "GRASS LOCATION PROJ_UNITS is:\n");
                    for (i_value = 0; i_value < loc_proj_units->nitems;
                            i_value++)
                        sprintf(error_msg + strlen(error_msg), "%s: %s\n",
                                loc_proj_units->key[i_value],
                                loc_proj_units->value[i_value]);
                    strcat(error_msg, "\n");
                }

                if (proj_units != NULL) {
                    strcat(error_msg, "Import dataset PROJ_UNITS is:\n");
                    for (i_value = 0; i_value < proj_units->nitems; i_value++)
                        sprintf(error_msg + strlen(error_msg), "%s: %s\n",
                                proj_units->key[i_value],
                                proj_units->value[i_value]);
                }
            }
            sprintf(error_msg + strlen(error_msg),
                    _("\nYou can use the -o flag to %s to override this projection check.\n"),
                    G_program_name());
            strcat(error_msg,
                   _("Consider generating a new location with 'location' parameter"
                     " from input data set.\n"));
            G_fatal_error(error_msg);
        }
        else {
            G_message(_("Projection of input dataset and current location "
                        "appear to match"));
        }
    }

    db_init_string(&sql);
    db_init_string(&strval);

    /* open output vector */
    /* strip any @mapset from vector output name */
    G_find_vector(output, G_mapset());
    Vect_open_new(&Map, output, flag.z->answer != 0);
    Out = &Map;

    n_polygon_boundaries = 0;
    if (!flag.no_clean->answer) {
        /* check if we need a tmp vector */

        /* estimate distance for boundary splitting --> */
        for (layer = 0; layer < nlayers; layer++) {
            layer_id = layers[layer];

            Ogr_layer = OGR_DS_GetLayer(Ogr_ds, layer_id);
            Ogr_featuredefn = OGR_L_GetLayerDefn(Ogr_layer);

            n_features = feature_count = 0;

            n_features = OGR_L_GetFeatureCount(Ogr_layer, 1);
            OGR_L_ResetReading(Ogr_layer);

            /* count polygons and isles */
            G_message(_("Counting polygons for %d features (OGR layer <%s>)..."),
                      n_features, layer_names[layer]);
            while ((Ogr_feature = OGR_L_GetNextFeature(Ogr_layer)) != NULL) {
                G_percent(feature_count++, n_features, 1);	/* show something happens */
                /* Geometry */
                Ogr_geometry = OGR_F_GetGeometryRef(Ogr_feature);
                if (Ogr_geometry != NULL) {
                    poly_count(Ogr_geometry, (type & GV_BOUNDARY));
                }
                OGR_F_Destroy(Ogr_feature);
            }
        }

        G_debug(1, "n polygon boundaries: %d", n_polygon_boundaries);
        if (n_polygon_boundaries > 50) {
            split_distance =
                area_size / log(n_polygon_boundaries);
            /* divisor is the handle: increase divisor to decrease split_distance */
            split_distance = split_distance / 5.;
            G_debug(1, "root of area size: %f", area_size);
            G_verbose_message(_("Boundary splitting distance in map units: %G"),
                              split_distance);
        }
        /* <-- estimate distance for boundary splitting */

        use_tmp_vect = n_polygon_boundaries > 0;

        if (use_tmp_vect) {
            /* open temporary vector, do the work in the temporary vector
             * at the end copy alive lines to output vector
             * in case of polygons this reduces the coor file size by a factor of 2 to 5
             * only needed when cleaning polygons */
            sprintf(tempvect, "%s_tmp", output);
            G_verbose_message(_("Using temporary vector <%s>"), tempvect);
            Vect_open_new(&Tmp, tempvect, flag.z->answer != 0);
            Out = &Tmp;
        }
    }

    Vect_hist_command(&Map);

    /* Points and lines are written immediately with categories. Boundaries of polygons are
     * written to the vector then cleaned and centroids are calculated for all areas in cleaan vector.
     * Then second pass through finds all centroids in each polygon feature and adds its category
     * to the centroid. The result is that one centroids may have 0, 1 ore more categories
     * of one ore more (more input layers) fields. */
    with_z = 0;
    for (layer = 0; layer < nlayers; layer++) {
        layer_id = layers[layer];

        Ogr_layer = OGR_DS_GetLayer(Ogr_ds, layer_id);
        Ogr_featuredefn = OGR_L_GetLayerDefn(Ogr_layer);

        /* Add DB link */
        if (!flag.notab->answer) {
            char *cat_col_name = GV_KEY_COLUMN;

            if (nlayers == 1) {	/* one layer only */
                Fi = Vect_default_field_info(&Map, layer + 1, NULL,
                                             GV_1TABLE);
            }
            else {
                Fi = Vect_default_field_info(&Map, layer + 1, NULL,
                                             GV_MTABLE);
            }

            if (ncnames > 0) {
                cat_col_name = param.cnames->answers[0];
            }
            Vect_map_add_dblink(&Map, layer + 1, layer_names[layer], Fi->table,
                                cat_col_name, Fi->database, Fi->driver);

            ncols = OGR_FD_GetFieldCount(Ogr_featuredefn);
            G_debug(2, "%d columns", ncols);

            /* Create table */
            sprintf(buf, "create table %s (%s integer", Fi->table,
                    cat_col_name);
            db_set_string(&sql, buf);
            for (i = 0; i < ncols; i++) {

                Ogr_field = OGR_FD_GetFieldDefn(Ogr_featuredefn, i);
                Ogr_ftype = OGR_Fld_GetType(Ogr_field);

                G_debug(3, "Ogr_ftype: %i", Ogr_ftype);	/* look up below */

                if (i < ncnames - 1) {
                    Ogr_fieldname = G_store(param.cnames->answers[i + 1]);
                }
                else {
                    /* Change column names to [A-Za-z][A-Za-z0-9_]* */
                    Ogr_fieldname = G_store(OGR_Fld_GetNameRef(Ogr_field));
                    G_debug(3, "Ogr_fieldname: '%s'", Ogr_fieldname);

                    G_str_to_sql(Ogr_fieldname);

                    G_debug(3, "Ogr_fieldname: '%s'", Ogr_fieldname);

                }

                /* avoid that we get the 'cat' column twice */
                if (strcmp(Ogr_fieldname, GV_KEY_COLUMN) == 0) {
                    sprintf(namebuf, "%s_", Ogr_fieldname);
                    Ogr_fieldname = G_store(namebuf);
                }

                /* captial column names are a pain in SQL */
                if (flag.tolower->answer)
                    G_str_to_lower(Ogr_fieldname);

                if (strcmp(OGR_Fld_GetNameRef(Ogr_field), Ogr_fieldname) != 0) {
                    G_warning(_("Column name changed: '%s' -> '%s'"),
                              OGR_Fld_GetNameRef(Ogr_field), Ogr_fieldname);
                }

                /** Simple 32bit integer                     OFTInteger = 0        **/

                /** List of 32bit integers                   OFTIntegerList = 1    **/

                /** Double Precision floating point          OFTReal = 2           **/

                /** List of doubles                          OFTRealList = 3       **/

                /** String of ASCII chars                    OFTString = 4         **/

                /** Array of strings                         OFTStringList = 5     **/

                /** Double byte string (unsupported)         OFTWideString = 6     **/

                /** List of wide strings (unsupported)       OFTWideStringList = 7 **/

                /** Raw Binary data (unsupported)            OFTBinary = 8         **/

                /**                                          OFTDate = 9           **/

                /**                                          OFTTime = 10          **/

                /**                                          OFTDateTime = 11      **/


                if (Ogr_ftype == OFTInteger) {
                    sprintf(buf, ", %s integer", Ogr_fieldname);
                }
                else if (Ogr_ftype == OFTIntegerList) {
                    /* hack: treat as string */
                    sprintf(buf, ", %s varchar ( %d )", Ogr_fieldname,
                            OFTIntegerListlength);
                    G_warning(_("Writing column <%s> with fixed length %d chars (may be truncated)"),
                              Ogr_fieldname, OFTIntegerListlength);
                }
                else if (Ogr_ftype == OFTReal) {
                    sprintf(buf, ", %s double precision", Ogr_fieldname);
#if GDAL_VERSION_NUM >= 1320
                }
                else if (Ogr_ftype == OFTDate) {
                    sprintf(buf, ", %s date", Ogr_fieldname);
                }
                else if (Ogr_ftype == OFTTime) {
                    sprintf(buf, ", %s time", Ogr_fieldname);
                }
                else if (Ogr_ftype == OFTDateTime) {
                    sprintf(buf, ", %s datetime", Ogr_fieldname);
#endif
                }
                else if (Ogr_ftype == OFTString) {
                    int fwidth;

                    fwidth = OGR_Fld_GetWidth(Ogr_field);
                    /* TODO: read all records first and find the longest string length */
                    if (fwidth == 0) {
                        G_warning(_("Width for column %s set to 255 (was not specified by OGR), "
                                    "some strings may be truncated!"),
                                  Ogr_fieldname);
                        fwidth = 255;
                    }
                    sprintf(buf, ", %s varchar ( %d )", Ogr_fieldname,
                            fwidth);
                }
                else if (Ogr_ftype == OFTStringList) {
                    /* hack: treat as string */
                    sprintf(buf, ", %s varchar ( %d )", Ogr_fieldname,
                            OFTIntegerListlength);
                    G_warning(_("Writing column %s with fixed length %d chars (may be truncated)"),
                              Ogr_fieldname, OFTIntegerListlength);
                }
                else {
                    G_warning(_("Column type not supported (%s)"),
                              Ogr_fieldname);
                    buf[0] = 0;
                }
                db_append_string(&sql, buf);
                G_free(Ogr_fieldname);
            }
            db_append_string(&sql, ")");
            G_debug(3, db_get_string(&sql));

            driver =
                db_start_driver_open_database(Fi->driver,
                                              Vect_subst_var(Fi->database,
                                                      &Map));
            if (driver == NULL) {
                G_fatal_error(_("Unable open database <%s> by driver <%s>"),
                              Vect_subst_var(Fi->database, &Map), Fi->driver);
            }

            if (db_execute_immediate(driver, &sql) != DB_OK) {
                db_close_database(driver);
                db_shutdown_driver(driver);
                G_fatal_error(_("Unable to create table: '%s'"),
                              db_get_string(&sql));
            }

            if (db_create_index2(driver, Fi->table, cat_col_name) != DB_OK)
                G_warning(_("Unable to create index for table <%s>, key <%s>"),
                          Fi->table, cat_col_name);

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

            db_begin_transaction(driver);
        }

        /* Import feature */
        cat = 1;
        nogeom = 0;
        OGR_L_ResetReading(Ogr_layer);
        n_features = feature_count = 0;

        n_features = OGR_L_GetFeatureCount(Ogr_layer, 1);

        G_important_message(_("Importing %d features (OGR layer <%s>)..."),
                            n_features, layer_names[layer]);
        while ((Ogr_feature = OGR_L_GetNextFeature(Ogr_layer)) != NULL) {
            G_percent(feature_count++, n_features, 1);	/* show something happens */
            /* Geometry */
            Ogr_geometry = OGR_F_GetGeometryRef(Ogr_feature);
            if (Ogr_geometry == NULL) {
                nogeom++;
            }
            else {
                dim = OGR_G_GetCoordinateDimension(Ogr_geometry);
                if (dim > 2)
                    with_z = 1;

                geom(Ogr_geometry, Out, layer + 1, cat, min_area, type,
                     flag.no_clean->answer);
            }

            /* Attributes */
            if (!flag.notab->answer) {
                sprintf(buf, "insert into %s values ( %d", Fi->table, cat);
                db_set_string(&sql, buf);
                for (i = 0; i < ncols; i++) {
                    Ogr_field = OGR_FD_GetFieldDefn(Ogr_featuredefn, i);
                    Ogr_ftype = OGR_Fld_GetType(Ogr_field);
                    if (OGR_F_IsFieldSet(Ogr_feature, i)) {
                        if (Ogr_ftype == OFTInteger || Ogr_ftype == OFTReal) {
                            sprintf(buf, ", %s",
                                    OGR_F_GetFieldAsString(Ogr_feature, i));
#if GDAL_VERSION_NUM >= 1320
                            /* should we use OGR_F_GetFieldAsDateTime() here ? */
                        }
                        else if (Ogr_ftype == OFTDate || Ogr_ftype == OFTTime
                                 || Ogr_ftype == OFTDateTime) {
                            char *newbuf;

                            db_set_string(&strval, (char *)
                                          OGR_F_GetFieldAsString(Ogr_feature,
                                                                 i));
                            db_double_quote_string(&strval);
                            sprintf(buf, ", '%s'", db_get_string(&strval));
                            newbuf = G_str_replace(buf, "/", "-");	/* fix 2001/10/21 to 2001-10-21 */
                            sprintf(buf, "%s", newbuf);
#endif
                        }
                        else if (Ogr_ftype == OFTString ||
                                 Ogr_ftype == OFTIntegerList) {
                            db_set_string(&strval, (char *)
                                          OGR_F_GetFieldAsString(Ogr_feature,
                                                                 i));
                            db_double_quote_string(&strval);
                            sprintf(buf, ", '%s'", db_get_string(&strval));
                        }

                    }
                    else {
                        /* G_warning (_("Column value not set" )); */
                        if (Ogr_ftype == OFTInteger || Ogr_ftype == OFTReal) {
                            sprintf(buf, ", NULL");
#if GDAL_VERSION_NUM >= 1320
                        }
                        else if (Ogr_ftype == OFTString ||
                                 Ogr_ftype == OFTIntegerList ||
                                 Ogr_ftype == OFTDate) {
#else
                        }
                        else if (Ogr_ftype == OFTString ||
                                 Ogr_ftype == OFTIntegerList) {
#endif
                            sprintf(buf, ", ''");
                        }
                    }
                    db_append_string(&sql, buf);
                }
                db_append_string(&sql, " )");
                G_debug(3, db_get_string(&sql));

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

            OGR_F_Destroy(Ogr_feature);
            cat++;
        }
        G_percent(1, 1, 1);	/* finish it */

        if (!flag.notab->answer) {
            db_commit_transaction(driver);
            db_close_database_shutdown_driver(driver);
        }

        if (nogeom > 0)
            G_warning(_("%d %s without geometry"), nogeom,
                      nogeom == 1 ? "feature" : "features");
    }


    separator = "-----------------------------------------------------";
    G_message("%s", separator);

    if (use_tmp_vect) {
        /* TODO: is it necessary to build here? probably not, consumes time */
        /* GV_BUILD_BASE is sufficient to toggle boundary cleaning */
        Vect_build_partial(&Tmp, GV_BUILD_BASE);
    }

    if (use_tmp_vect && !flag.no_clean->answer &&
            Vect_get_num_primitives(Out, GV_BOUNDARY) > 0) {
        int ret, centr, ncentr, otype, n_overlaps, n_nocat;
        CENTR *Centr;
        struct spatial_index si;
        double x, y, total_area, overlap_area, nocat_area;
        struct bound_box box;
        struct line_pnts *Points;
        int nmodif;

        Points = Vect_new_line_struct();

        G_message("%s", separator);

        G_warning(_("Cleaning polygons, result is not guaranteed!"));

        if (snap >= 0) {
            G_message("%s", separator);
            G_message(_("Snapping boundaries (threshold = %.3e)..."), snap);
            Vect_snap_lines(&Tmp, GV_BOUNDARY, snap, NULL);
        }

        /* It is not to clean to snap centroids, but I have seen data with 2 duplicate polygons
         * (as far as decimal places were printed) and centroids were not identical */
        /* Disabled, because overlapping polygons result in many duplicate centroids anyway */
        /*
           fprintf ( stderr, separator );
           fprintf ( stderr, "Snap centroids (threshold 0.000001):\n" );
           Vect_snap_lines ( &Map, GV_CENTROID, 0.000001, NULL, stderr );
         */

        G_message("%s", separator);
        G_message(_("Breaking polygons..."));
        Vect_break_polygons(&Tmp, GV_BOUNDARY, NULL);

        /* It is important to remove also duplicate centroids in case of duplicate input polygons */
        G_message("%s", separator);
        G_message(_("Removing duplicates..."));
        Vect_remove_duplicates(&Tmp, GV_BOUNDARY | GV_CENTROID, NULL);

        /* in non-pathological cases, the bulk of the cleaning is now done */

        /* Vect_clean_small_angles_at_nodes() can change the geometry so that new intersections
         * are created. We must call Vect_break_lines(), Vect_remove_duplicates()
         * and Vect_clean_small_angles_at_nodes() until no more small angles are found */
        do {
            G_message("%s", separator);
            G_message(_("Breaking boundaries..."));
            Vect_break_lines(&Tmp, GV_BOUNDARY, NULL);

            G_message("%s", separator);
            G_message(_("Removing duplicates..."));
            Vect_remove_duplicates(&Tmp, GV_BOUNDARY, NULL);

            G_message("%s", separator);
            G_message(_("Cleaning boundaries at nodes..."));
            nmodif =
                Vect_clean_small_angles_at_nodes(&Tmp, GV_BOUNDARY, NULL);
        } while (nmodif > 0);

        /* merge boundaries */
        G_message("%s", separator);
        G_message(_("Merging boundaries..."));
        Vect_merge_lines(&Tmp, GV_BOUNDARY, NULL, NULL);

        G_message("%s", separator);
        if (type & GV_BOUNDARY) {	/* that means lines were converted to boundaries */
            G_message(_("Changing boundary dangles to lines..."));
            Vect_chtype_dangles(&Tmp, -1.0, NULL);
        }
        else {
            G_message(_("Removing dangles..."));
            Vect_remove_dangles(&Tmp, GV_BOUNDARY, -1.0, NULL);
        }

        G_message("%s", separator);
        if (type & GV_BOUNDARY) {
            G_message(_("Changing boundary bridges to lines..."));
            Vect_chtype_bridges(&Tmp, NULL);
        }
        else {
            G_message(_("Removing bridges..."));
            Vect_remove_bridges(&Tmp, NULL);
        }

        /* Boundaries are hopefully clean, build areas */
        G_message("%s", separator);
        Vect_build_partial(&Tmp, GV_BUILD_ATTACH_ISLES);

        /* Calculate new centroids for all areas, centroids have the same id as area */
        ncentr = Vect_get_num_areas(&Tmp);
        G_debug(3, "%d centroids/areas", ncentr);

        Centr = (CENTR *) G_calloc(ncentr + 1, sizeof(CENTR));
        Vect_spatial_index_init(&si, 0);
        for (centr = 1; centr <= ncentr; centr++) {
            Centr[centr].valid = 0;
            Centr[centr].cats = Vect_new_cats_struct();
            ret = Vect_get_point_in_area(&Tmp, centr, &x, &y);
            if (ret < 0) {
                G_warning(_("Unable to calculate area centroid"));
                continue;
            }

            Centr[centr].x = x;
            Centr[centr].y = y;
            Centr[centr].valid = 1;
            box.N = box.S = y;
            box.E = box.W = x;
            box.T = box.B = 0;
            Vect_spatial_index_add_item(&si, centr, &box);
        }

        /* Go through all layers and find centroids for each polygon */
        for (layer = 0; layer < nlayers; layer++) {
            G_message("%s", separator);
            G_message(_("Finding centroids for OGR layer <%s>..."), layer_names[layer]);
            layer_id = layers[layer];
            Ogr_layer = OGR_DS_GetLayer(Ogr_ds, layer_id);
            n_features = OGR_L_GetFeatureCount(Ogr_layer, 1);
            OGR_L_ResetReading(Ogr_layer);

            cat = 0;		/* field = layer + 1 */
            G_percent(cat, n_features, 2);
            while ((Ogr_feature = OGR_L_GetNextFeature(Ogr_layer)) != NULL) {
                cat++;
                G_percent(cat, n_features, 2);
                /* Geometry */
                Ogr_geometry = OGR_F_GetGeometryRef(Ogr_feature);
                if (Ogr_geometry != NULL) {
                    centroid(Ogr_geometry, Centr, &si, layer + 1, cat,
                             min_area, type);
                }

                OGR_F_Destroy(Ogr_feature);
            }
        }

        /* Write centroids */
        G_message("%s", separator);
        G_message(_("Writing centroids..."));

        n_overlaps = n_nocat = 0;
        total_area = overlap_area = nocat_area = 0.0;
        for (centr = 1; centr <= ncentr; centr++) {
            double area;

            G_percent(centr, ncentr, 2);

            area = Vect_get_area_area(&Tmp, centr);
            total_area += area;

            if (!(Centr[centr].valid)) {
                continue;
            }

            if (Centr[centr].cats->n_cats == 0) {
                nocat_area += area;
                n_nocat++;
                continue;
            }

            if (Centr[centr].cats->n_cats > 1) {
                Vect_cat_set(Centr[centr].cats, nlayers + 1,
                             Centr[centr].cats->n_cats);
                overlap_area += area;
                n_overlaps++;
            }

            Vect_reset_line(Points);
            Vect_append_point(Points, Centr[centr].x, Centr[centr].y, 0.0);
            if (type & GV_POINT)
                otype = GV_POINT;
            else
                otype = GV_CENTROID;
            Vect_write_line(&Tmp, otype, Points, Centr[centr].cats);
        }
        if (Centr)
            G_free(Centr);

        Vect_spatial_index_destroy(&si);

        if (n_overlaps > 0) {
            G_warning(_("%d areas represent more (overlapping) features, because polygons overlap "
                        "in input layer(s). Such areas are linked to more than 1 row in attribute table. "
                        "The number of features for those areas is stored as category in layer %d"),
                      n_overlaps, nlayers + 1);
        }

        G_message("%s", separator);

        Vect_hist_write(&Map, separator);
        Vect_hist_write(&Map, "\n");
        sprintf(buf, _("%d input polygons\n"), n_polygons);
        G_message(_("%d input polygons"), n_polygons);
        Vect_hist_write(&Map, buf);

        sprintf(buf, _("Total area: %G (%d areas)\n"), total_area, ncentr);
        G_message(_("Total area: %G (%d areas)"), total_area, ncentr);
        Vect_hist_write(&Map, buf);

        sprintf(buf, _("Overlapping area: %G (%d areas)\n"), overlap_area,
                n_overlaps);
        G_message(_("Overlapping area: %G (%d areas)"), overlap_area,
                  n_overlaps);
        Vect_hist_write(&Map, buf);

        sprintf(buf, _("Area without category: %G (%d areas)\n"), nocat_area,
                n_nocat);
        G_message(_("Area without category: %G (%d areas)"), nocat_area,
                  n_nocat);
        Vect_hist_write(&Map, buf);
        G_message("%s", separator);
    }

    /* needed?
     * OGR_DS_Destroy( Ogr_ds );
     */

    if (use_tmp_vect) {
        /* Copy temporary vector to output vector */
        Vect_copy_map_lines(&Tmp, &Map);
        /* release memory occupied by topo, we may need that memory for main output */
        Vect_set_release_support(&Tmp);
        Vect_close(&Tmp);
        Vect_delete(tempvect);
    }

    Vect_build(&Map);
    Vect_close(&Map);

    /* -------------------------------------------------------------------- */
    /*      Extend current window based on dataset.                         */
    /* -------------------------------------------------------------------- */
    if (flag.extend->answer) {
        G_get_default_window(&loc_wind);

        loc_wind.north = MAX(loc_wind.north, cellhd.north);
        loc_wind.south = MIN(loc_wind.south, cellhd.south);
        loc_wind.west = MIN(loc_wind.west, cellhd.west);
        loc_wind.east = MAX(loc_wind.east, cellhd.east);

        loc_wind.rows = (int)ceil((loc_wind.north - loc_wind.south)
                                  / loc_wind.ns_res);
        loc_wind.south = loc_wind.north - loc_wind.rows * loc_wind.ns_res;

        loc_wind.cols = (int)ceil((loc_wind.east - loc_wind.west)
                                  / loc_wind.ew_res);
        loc_wind.east = loc_wind.west + loc_wind.cols * loc_wind.ew_res;

        G__put_window(&loc_wind, "../PERMANENT", "DEFAULT_WIND");
    }

    if (with_z && !flag.z->answer)
        G_warning(_("Input data contains 3D features. Created vector is 2D only, "
                    "use -z flag to import 3D vector."));

    exit(EXIT_SUCCESS);
}
Beispiel #6
0
int main(int argc, char *argv[])
{
    struct Map_info In, Out, Buf;
    struct line_pnts *Points;
    struct line_cats *Cats, *BCats;
    char bufname[GNAME_MAX];
    struct GModule *module;
    struct Option *in_opt, *out_opt, *type_opt, *dista_opt, *distb_opt,
	*angle_opt;
    struct Flag *straight_flag, *nocaps_flag;
    struct Option *tol_opt, *bufcol_opt, *scale_opt, *field_opt;

    int verbose;
    double da, db, dalpha, tolerance, unit_tolerance;
    int type;
    int i, ret, nareas, area, nlines, line;
    char *Areas, *Lines;
    int field;
    struct buf_contours *arr_bc;
    struct buf_contours_pts arr_bc_pts;
    int buffers_count = 0, line_id;
    struct spatial_index si;
    struct bound_box bbox;

    /* Attributes if sizecol is used */
    int nrec, ctype;
    struct field_info *Fi;
    dbDriver *Driver;
    dbCatValArray cvarr;
    double size_val, scale;


    module = G_define_module();
    G_add_keyword(_("vector"));
    G_add_keyword(_("geometry"));
    G_add_keyword(_("buffer"));
    module->description =
	_("Creates a buffer around vector features of given type.");

    in_opt = G_define_standard_option(G_OPT_V_INPUT);

    field_opt = G_define_standard_option(G_OPT_V_FIELD_ALL);
    field_opt->guisection = _("Selection");

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

    out_opt = G_define_standard_option(G_OPT_V_OUTPUT);
    
    dista_opt = G_define_option();
    dista_opt->key = "distance";
    dista_opt->type = TYPE_DOUBLE;
    dista_opt->required = NO;
    dista_opt->description =
	_("Buffer distance along major axis in map units");
    dista_opt->guisection = _("Distance");

    distb_opt = G_define_option();
    distb_opt->key = "minordistance";
    distb_opt->type = TYPE_DOUBLE;
    distb_opt->required = NO;
    distb_opt->description =
	_("Buffer distance along minor axis in map units");
    distb_opt->guisection = _("Distance");

    angle_opt = G_define_option();
    angle_opt->key = "angle";
    angle_opt->type = TYPE_DOUBLE;
    angle_opt->required = NO;
    angle_opt->answer = "0";
    angle_opt->description = _("Angle of major axis in degrees");
    angle_opt->guisection = _("Distance");

    bufcol_opt = G_define_standard_option(G_OPT_DB_COLUMN);
    bufcol_opt->key = "bufcolumn";
    bufcol_opt->description =
	_("Name of column to use for buffer distances");
    bufcol_opt->guisection = _("Distance");

    scale_opt = G_define_option();
    scale_opt->key = "scale";
    scale_opt->type = TYPE_DOUBLE;
    scale_opt->required = NO;
    scale_opt->answer = "1.0";
    scale_opt->description = _("Scaling factor for attribute column values");
    scale_opt->guisection = _("Distance");

    tol_opt = G_define_option();
    tol_opt->key = "tolerance";
    tol_opt->type = TYPE_DOUBLE;
    tol_opt->required = NO;
    tol_opt->answer = "0.01";
    tol_opt->description =
	_("Maximum distance between theoretical arc and polygon segments as multiple of buffer");
    tol_opt->guisection = _("Distance");

    straight_flag = G_define_flag();
    straight_flag->key = 's';
    straight_flag->description = _("Make outside corners straight");

    nocaps_flag = G_define_flag();
    nocaps_flag->key = 'c';
    nocaps_flag->description = _("Don't make caps at the ends of polylines");

    G_gisinit(argv[0]);
    
    if (G_parser(argc, argv))
	exit(EXIT_FAILURE);

    type = Vect_option_to_types(type_opt);

    if ((dista_opt->answer && bufcol_opt->answer) ||
	(!(dista_opt->answer || bufcol_opt->answer)))
	G_fatal_error(_("Select a buffer distance/minordistance/angle "
			"or column, but not both."));

    if (bufcol_opt->answer)
	G_warning(_("The bufcol option may contain bugs during the cleaning "
		    "step. If you encounter problems, use the debug "
		    "option or clean manually with v.clean tool=break; "
		    "v.category step=0; v.extract -d type=area"));

    if (field_opt->answer)
	field = Vect_get_field_number(&In, field_opt->answer);
    else
	field = -1;
	
    if (bufcol_opt->answer && field == -1)
	G_fatal_error(_("The bufcol option requires a valid layer."));

    tolerance = atof(tol_opt->answer);
    if (tolerance <= 0)
	G_fatal_error(_("The tolerance must be > 0."));

    if (adjust_tolerance(&tolerance))
	G_warning(_("The tolerance was reset to %g"), tolerance);

    scale = atof(scale_opt->answer);
    if (scale <= 0.0)
	G_fatal_error("Illegal scale value");

    da = db = dalpha = 0;
    if (dista_opt->answer) {
	da = atof(dista_opt->answer);

	if (distb_opt->answer)
	    db = atof(distb_opt->answer);
	else
	    db = da;

	if (angle_opt->answer)
	    dalpha = atof(angle_opt->answer);
	else
	    dalpha = 0;

	unit_tolerance = tolerance * MIN(da, db);
	G_verbose_message(_("The tolerance in map units = %g"), unit_tolerance);
    }

    Vect_check_input_output_name(in_opt->answer, out_opt->answer,
				 GV_FATAL_EXIT);

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

    Vect_set_open_level(2); /* topology required */

    if (1 > Vect_open_old2(&In, in_opt->answer, "", field_opt->answer))
	G_fatal_error(_("Unable to open vector map <%s>"), in_opt->answer);

    if (0 > Vect_open_new(&Out, out_opt->answer, WITHOUT_Z)) {
	Vect_close(&In);
	G_fatal_error(_("Unable to create vector map <%s>"), out_opt->answer);
    }

    /* open tmp vector for buffers, needed for cleaning */
    sprintf(bufname, "%s_tmp_%d", out_opt->answer, getpid());
    if (0 > Vect_open_new(&Buf, bufname, 0)) {
	Vect_close(&In);
	Vect_close(&Out);
	Vect_delete(out_opt->answer);
	exit(EXIT_FAILURE);
    }
    Vect_build_partial(&Buf, GV_BUILD_BASE);

    /* check and load attribute column data */
    if (bufcol_opt->answer) {
	db_CatValArray_init(&cvarr);

	Fi = Vect_get_field(&In, field);
	if (Fi == NULL)
	    G_fatal_error(_("Database connection not defined for layer %d"),
			  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);

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

	/* TODO: only select values we need instead of all in column */
	nrec =
	    db_select_CatValArray(Driver, Fi->table, Fi->key,
				  bufcol_opt->answer, NULL, &cvarr);
	if (nrec < 0)
	    G_fatal_error(_("Unable to select data from table <%s>"),
			  Fi->table);
	G_debug(2, "%d records selected from table", nrec);

	ctype = cvarr.ctype;
	if (ctype != DB_C_TYPE_INT && ctype != DB_C_TYPE_DOUBLE)
	    G_fatal_error(_("Column type not supported"));

	db_close_database_shutdown_driver(Driver);

	/* Output cats/values list */
	for (i = 0; i < cvarr.n_values; i++) {
	    if (ctype == DB_C_TYPE_INT) {
		G_debug(4, "cat = %d val = %d", cvarr.value[i].cat,
			cvarr.value[i].val.i);
	    }
	    else if (ctype == DB_C_TYPE_DOUBLE) {
		G_debug(4, "cat = %d val = %f", cvarr.value[i].cat,
			cvarr.value[i].val.d);
	    }
	}
    }

    Vect_copy_head_data(&In, &Out);
    Vect_hist_copy(&In, &Out);
    Vect_hist_command(&Out);


    /* Create buffers' boundaries */
    nlines = nareas = 0;
    if ((type & GV_POINTS) || (type & GV_LINES))
	nlines += Vect_get_num_primitives(&In, type);
    if (type & GV_AREA)
	nareas = Vect_get_num_areas(&In);
    
    if (nlines + nareas == 0) {
	G_warning(_("No features available for buffering. "
	            "Check type option and features available in the input vector."));
	exit(EXIT_SUCCESS);
    }

    buffers_count = 1;
    arr_bc = G_malloc((nlines + nareas + 1) * sizeof(struct buf_contours));

    Vect_spatial_index_init(&si, 0);

    /* Lines (and Points) */
    if ((type & GV_POINTS) || (type & GV_LINES)) {
	int ltype;

	if (nlines > 0)
	    G_message(_("Buffering lines..."));
	for (line = 1; line <= nlines; line++) {
	    int cat;

	    G_debug(2, "line = %d", line);
	    G_percent(line, nlines, 2);
	    
	    if (!Vect_line_alive(&In, line))
		continue;

	    ltype = Vect_read_line(&In, Points, Cats, line);
	    if (!(ltype & type))
		continue;

	    if (field > 0 && !Vect_cat_get(Cats, field, &cat))
		continue;

	    if (bufcol_opt->answer) {
		ret = db_CatValArray_get_value_di(&cvarr, cat, &size_val);
		if (ret != DB_OK) {
		    G_warning(_("No record for category %d in table <%s>"),
			      cat, Fi->table);
		    continue;
		}

		if (size_val < 0.0) {
		    G_warning(_("Attribute is of invalid size (%.3f) for category %d"),
			      size_val, cat);
		    continue;
		}

		if (size_val == 0.0)
		    continue;

		da = size_val * scale;
		db = da;
		dalpha = 0;
		unit_tolerance = tolerance * MIN(da, db);

		G_debug(2, "    dynamic buffer size = %.2f", da);
		G_debug(2, _("The tolerance in map units: %g"),
			unit_tolerance);
	    }
	    
	    Vect_line_prune(Points);
	    if (ltype & GV_POINTS || Points->n_points == 1) {
		Vect_point_buffer2(Points->x[0], Points->y[0], da, db, dalpha,
				   !(straight_flag->answer), unit_tolerance,
				   &(arr_bc_pts.oPoints));

		Vect_write_line(&Out, GV_BOUNDARY, arr_bc_pts.oPoints, BCats);
		line_id = Vect_write_line(&Buf, GV_BOUNDARY, arr_bc_pts.oPoints, Cats);
		Vect_destroy_line_struct(arr_bc_pts.oPoints);
		/* add buffer to spatial index */
		Vect_get_line_box(&Buf, line_id, &bbox);
		Vect_spatial_index_add_item(&si, buffers_count, &bbox);
		arr_bc[buffers_count].outer = line_id;
		arr_bc[buffers_count].inner_count = 0;
		arr_bc[buffers_count].inner = NULL;
		buffers_count++;

	    }
	    else {
		Vect_line_buffer2(Points, da, db, dalpha,
				  !(straight_flag->answer),
				  !(nocaps_flag->answer), unit_tolerance,
				  &(arr_bc_pts.oPoints),
				  &(arr_bc_pts.iPoints),
				  &(arr_bc_pts.inner_count));

		Vect_write_line(&Out, GV_BOUNDARY, arr_bc_pts.oPoints, BCats);
		line_id = Vect_write_line(&Buf, GV_BOUNDARY, arr_bc_pts.oPoints, Cats);
		Vect_destroy_line_struct(arr_bc_pts.oPoints);
		/* add buffer to spatial index */
		Vect_get_line_box(&Buf, line_id, &bbox);
		Vect_spatial_index_add_item(&si, buffers_count, &bbox);
		arr_bc[buffers_count].outer = line_id;

		arr_bc[buffers_count].inner_count = arr_bc_pts.inner_count;
		if (arr_bc_pts.inner_count > 0) {
		    arr_bc[buffers_count].inner = G_malloc(arr_bc_pts.inner_count * sizeof(int));
		    for (i = 0; i < arr_bc_pts.inner_count; i++) {
			Vect_write_line(&Out, GV_BOUNDARY, arr_bc_pts.iPoints[i], BCats);
			line_id = Vect_write_line(&Buf, GV_BOUNDARY, arr_bc_pts.iPoints[i], Cats);
			Vect_destroy_line_struct(arr_bc_pts.iPoints[i]);
			/* add buffer to spatial index */
			Vect_get_line_box(&Buf, line_id, &bbox);
			Vect_spatial_index_add_item(&si, buffers_count, &bbox);
			arr_bc[buffers_count].inner[i] = line_id;
		    }
		    G_free(arr_bc_pts.iPoints);
		}
		buffers_count++;
	    }
	}
    }

    /* Areas */
    if (type & GV_AREA) {
	int centroid;

	if (nareas > 0) 
	    G_message(_("Buffering areas..."));
	for (area = 1; area <= nareas; area++) {
	    int cat;

	    G_percent(area, nareas, 2);
	    
	    if (!Vect_area_alive(&In, area))
		continue;
	    
	    centroid = Vect_get_area_centroid(&In, area);
	    if (centroid == 0)
		continue;

	    Vect_read_line(&In, NULL, Cats, centroid);
	    if (field > 0 && !Vect_cat_get(Cats, field, &cat))
		continue;

	    if (bufcol_opt->answer) {
		ret = db_CatValArray_get_value_di(&cvarr, cat, &size_val);
		if (ret != DB_OK) {
		    G_warning(_("No record for category %d in table <%s>"),
			      cat, Fi->table);
		    continue;
		}

		if (size_val < 0.0) {
		    G_warning(_("Attribute is of invalid size (%.3f) for category %d"),
			      size_val, cat);
		    continue;
		}

		if (size_val == 0.0)
		    continue;

		da = size_val * scale;
		db = da;
		dalpha = 0;
		unit_tolerance = tolerance * MIN(da, db);

		G_debug(2, "    dynamic buffer size = %.2f", da);
		G_debug(2, _("The tolerance in map units: %g"),
			unit_tolerance);
	    }

	    Vect_area_buffer2(&In, area, da, db, dalpha,
			      !(straight_flag->answer),
			      !(nocaps_flag->answer), unit_tolerance,
			      &(arr_bc_pts.oPoints),
			      &(arr_bc_pts.iPoints),
			      &(arr_bc_pts.inner_count));

	    Vect_write_line(&Out, GV_BOUNDARY, arr_bc_pts.oPoints, BCats);
	    line_id = Vect_write_line(&Buf, GV_BOUNDARY, arr_bc_pts.oPoints, Cats);
	    Vect_destroy_line_struct(arr_bc_pts.oPoints);
	    /* add buffer to spatial index */
	    Vect_get_line_box(&Buf, line_id, &bbox);
	    Vect_spatial_index_add_item(&si, buffers_count, &bbox);
	    arr_bc[buffers_count].outer = line_id;

	    arr_bc[buffers_count].inner_count = arr_bc_pts.inner_count;
	    if (arr_bc_pts.inner_count > 0) {
		arr_bc[buffers_count].inner = G_malloc(arr_bc_pts.inner_count * sizeof(int));
		for (i = 0; i < arr_bc_pts.inner_count; i++) {
		    Vect_write_line(&Out, GV_BOUNDARY, arr_bc_pts.iPoints[i], BCats);
		    line_id = Vect_write_line(&Buf, GV_BOUNDARY, arr_bc_pts.iPoints[i], Cats);
		    Vect_destroy_line_struct(arr_bc_pts.iPoints[i]);
		    /* add buffer to spatial index */
		    Vect_get_line_box(&Buf, line_id, &bbox);
		    Vect_spatial_index_add_item(&si, buffers_count, &bbox);
		    arr_bc[buffers_count].inner[i] = line_id;
		}
		G_free(arr_bc_pts.iPoints);
	    }
	    buffers_count++;
	}
    }

    verbose = G_verbose();

    G_message(_("Cleaning buffers..."));
    
    /* Break lines */
    G_message(_("Building parts of topology..."));
    Vect_build_partial(&Out, GV_BUILD_BASE);

    G_message(_("Snapping boundaries..."));
    Vect_snap_lines(&Out, GV_BOUNDARY, 1e-7, NULL);

    G_message(_("Breaking polygons..."));
    Vect_break_polygons(&Out, GV_BOUNDARY, NULL);

    G_message(_("Removing duplicates..."));
    Vect_remove_duplicates(&Out, GV_BOUNDARY, NULL);

    do {
	G_message(_("Breaking boundaries..."));
	Vect_break_lines(&Out, GV_BOUNDARY, NULL);

	G_message(_("Removing duplicates..."));
	Vect_remove_duplicates(&Out, GV_BOUNDARY, NULL);

	G_message(_("Cleaning boundaries at nodes"));

    } while (Vect_clean_small_angles_at_nodes(&Out, GV_BOUNDARY, NULL) > 0);

    /* Dangles and bridges don't seem to be necessary if snapping is small enough. */
    /* Still needed for larger buffer distances ? */

    /*
    G_message(_("Removing dangles..."));
    Vect_remove_dangles(&Out, GV_BOUNDARY, -1, NULL);

    G_message (_("Removing bridges..."));
    Vect_remove_bridges(&Out, NULL);
    */

    G_message(_("Attaching islands..."));
    Vect_build_partial(&Out, GV_BUILD_ATTACH_ISLES);

    /* Calculate new centroids for all areas */
    nareas = Vect_get_num_areas(&Out);
    Areas = (char *)G_calloc(nareas + 1, sizeof(char));
    G_message(_("Calculating centroids for areas..."));
    G_percent(0, nareas, 2);
    for (area = 1; area <= nareas; area++) {
	double x, y;

	G_percent(area, nareas, 2);

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

	if (!Vect_area_alive(&Out, area))
	    continue;

	ret = Vect_get_point_in_area(&Out, area, &x, &y);
	if (ret < 0) {
	    G_warning(_("Cannot calculate area centroid"));
	    continue;
	}

	ret = point_in_buffer(arr_bc, &si, &Buf, x, y);

	if (ret) {
	    G_debug(3, "  -> in buffer");
	    Areas[area] = 1;
	}
    }

    /* Make a list of boundaries to be deleted (both sides inside) */
    nlines = Vect_get_num_lines(&Out);
    G_debug(3, "nlines = %d", nlines);
    Lines = (char *)G_calloc(nlines + 1, sizeof(char));

    G_message(_("Generating list of boundaries to be deleted..."));
    for (line = 1; line <= nlines; line++) {
	int j, side[2], areas[2];

	G_percent(line, nlines, 2);

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

	if (!Vect_line_alive(&Out, line))
	    continue;

	Vect_get_line_areas(&Out, line, &side[0], &side[1]);

	for (j = 0; j < 2; j++) {
	    if (side[j] == 0) {	/* area/isle not build */
		areas[j] = 0;
	    }
	    else if (side[j] > 0) {	/* area */
		areas[j] = side[j];
	    }
	    else {		/* < 0 -> island */
		areas[j] = Vect_get_isle_area(&Out, abs(side[j]));
	    }
	}

	G_debug(3, " areas = %d , %d -> Areas = %d, %d", areas[0], areas[1],
		Areas[areas[0]], Areas[areas[1]]);
	if (Areas[areas[0]] && Areas[areas[1]])
	    Lines[line] = 1;
    }
    G_free(Areas);

    /* Delete boundaries */
    G_message(_("Deleting boundaries..."));
    for (line = 1; line <= nlines; line++) {
	G_percent(line, nlines, 2);
	
	if (!Vect_line_alive(&Out, line))
	    continue;

	if (Lines[line]) {
	    G_debug(3, " delete line %d", line);
	    Vect_delete_line(&Out, line);
	}
	else {
	    /* delete incorrect boundaries */
	    int side[2];

	    Vect_get_line_areas(&Out, line, &side[0], &side[1]);
	    
	    if (!side[0] && !side[1])
		Vect_delete_line(&Out, line);
	}
    }

    G_free(Lines);

    /* Create new centroids */
    Vect_reset_cats(Cats);
    Vect_cat_set(Cats, 1, 1);
    nareas = Vect_get_num_areas(&Out);

    G_message(_("Calculating centroids for areas..."));    
    for (area = 1; area <= nareas; area++) {
	double x, y;

	G_percent(area, nareas, 2);

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

	if (!Vect_area_alive(&Out, area))
	    continue;

	ret = Vect_get_point_in_area(&Out, area, &x, &y);
	if (ret < 0) {
	    G_warning(_("Cannot calculate area centroid"));
	    continue;
	}

	ret = point_in_buffer(arr_bc, &si, &Buf, x, y);

	if (ret) {
	    Vect_reset_line(Points);
	    Vect_append_point(Points, x, y, 0.);
	    Vect_write_line(&Out, GV_CENTROID, Points, Cats);
	}
    }

    /* free arr_bc[] */
    /* will only slow down the module
       for (i = 0; i < buffers_count; i++) {
       Vect_destroy_line_struct(arr_bc[i].oPoints);
       for (j = 0; j < arr_bc[i].inner_count; j++)
       Vect_destroy_line_struct(arr_bc[i].iPoints[j]);
       G_free(arr_bc[i].iPoints);
       } */

    Vect_spatial_index_destroy(&si);
    Vect_close(&Buf);
    Vect_delete(bufname);

    G_set_verbose(verbose);

    Vect_close(&In);

    Vect_build_partial(&Out, GV_BUILD_NONE);
    Vect_build(&Out);
    Vect_close(&Out);

    exit(EXIT_SUCCESS);
}
Beispiel #7
0
int main(int argc, char *argv[])
{
    struct Map_info In, Out, Error;
    struct line_pnts *Points;
    struct line_cats *Cats;
    int i, type, iter;
    struct GModule *module;	/* GRASS module for parsing arguments */
    struct Option *map_in, *map_out, *error_out, *thresh_opt, *method_opt,
	*look_ahead_opt;
    struct Option *iterations_opt, *cat_opt, *alpha_opt, *beta_opt, *type_opt;
    struct Option *field_opt, *where_opt, *reduction_opt, *slide_opt;
    struct Option *angle_thresh_opt, *degree_thresh_opt,
	*closeness_thresh_opt;
    struct Option *betweeness_thresh_opt;
    struct Flag *notab_flag, *loop_support_flag;
    int with_z;
    int total_input, total_output;	/* Number of points in the input/output map respectively */
    double thresh, alpha, beta, reduction, slide, angle_thresh;
    double degree_thresh, closeness_thresh, betweeness_thresh;
    int method;
    int look_ahead, iterations;
    int loop_support;
    int layer;
    int n_lines;
    int simplification, mask_type;
    struct cat_list *cat_list = NULL;
    char *s, *descriptions;

    /* initialize GIS environment */
    G_gisinit(argv[0]);		/* reads grass env, stores program name to G_program_name() */

    /* initialize module */
    module = G_define_module();
    G_add_keyword(_("vector"));
    G_add_keyword(_("generalization"));
    G_add_keyword(_("simplification"));
    G_add_keyword(_("smoothing"));
    G_add_keyword(_("displacement"));
    G_add_keyword(_("network generalization"));
    module->description = _("Performs vector based generalization.");

    /* Define the different options as defined in gis.h */
    map_in = G_define_standard_option(G_OPT_V_INPUT);

    field_opt = G_define_standard_option(G_OPT_V_FIELD_ALL);

    type_opt = G_define_standard_option(G_OPT_V_TYPE);
    type_opt->options = "line,boundary,area";
    type_opt->answer = "line,boundary,area";
    type_opt->guisection = _("Selection");
    
    map_out = G_define_standard_option(G_OPT_V_OUTPUT);

    error_out = G_define_standard_option(G_OPT_V_OUTPUT);
    error_out->key = "error";
    error_out->required = NO;
    error_out->description =
	_("Error map of all lines and boundaries not being generalized due to topology issues or over-simplification");

    method_opt = G_define_option();
    method_opt->key = "method";
    method_opt->type = TYPE_STRING;
    method_opt->required = YES;
    method_opt->multiple = NO;
    method_opt->options =
	"douglas,douglas_reduction,lang,reduction,reumann,boyle,sliding_averaging,distance_weighting,chaiken,hermite,snakes,network,displacement";
    descriptions = NULL;
    G_asprintf(&descriptions,
               "douglas;%s;"
               "douglas_reduction;%s;"
               "lang;%s;"
               "reduction;%s;"
               "reumann;%s;"
               "boyle;%s;"
               "sliding_averaging;%s;"
               "distance_weighting;%s;"
               "chaiken;%s;"
               "hermite;%s;"
               "snakes;%s;"
               "network;%s;"
               "displacement;%s;",
               _("Douglas-Peucker Algorithm"),
               _("Douglas-Peucker Algorithm with reduction parameter"),
               _("Lang Simplification Algorithm"),
               _("Vertex Reduction Algorithm eliminates points close to each other"),
               _("Reumann-Witkam Algorithm"),
               _("Boyle's Forward-Looking Algorithm"),
               _("McMaster's Sliding Averaging Algorithm"),
               _("McMaster's Distance-Weighting Algorithm"),
               _("Chaiken's Algorithm"),
               _("Interpolation by Cubic Hermite Splines"),
               _("Snakes method for line smoothing"),
               _("Network generalization"),
               _("Displacement of lines close to each other"));
    method_opt->descriptions = G_store(descriptions);
    
    method_opt->description = _("Generalization algorithm");

    thresh_opt = G_define_option();
    thresh_opt->key = "threshold";
    thresh_opt->type = TYPE_DOUBLE;
    thresh_opt->required = YES;
    thresh_opt->options = "0-1000000000";
    thresh_opt->description = _("Maximal tolerance value");

    look_ahead_opt = G_define_option();
    look_ahead_opt->key = "look_ahead";
    look_ahead_opt->type = TYPE_INTEGER;
    look_ahead_opt->required = NO;
    look_ahead_opt->answer = "7";
    look_ahead_opt->description = _("Look-ahead parameter");

    reduction_opt = G_define_option();
    reduction_opt->key = "reduction";
    reduction_opt->type = TYPE_DOUBLE;
    reduction_opt->required = NO;
    reduction_opt->answer = "50";
    reduction_opt->options = "0-100";
    reduction_opt->description =
	_("Percentage of the points in the output of 'douglas_reduction' algorithm");
    
    slide_opt = G_define_option();
    slide_opt->key = "slide";
    slide_opt->type = TYPE_DOUBLE;
    slide_opt->required = NO;
    slide_opt->answer = "0.5";
    slide_opt->options = "0-1";
    slide_opt->description =
	_("Slide of computed point toward the original point");

    angle_thresh_opt = G_define_option();
    angle_thresh_opt->key = "angle_thresh";
    angle_thresh_opt->type = TYPE_DOUBLE;
    angle_thresh_opt->required = NO;
    angle_thresh_opt->answer = "3";
    angle_thresh_opt->options = "0-180";
    angle_thresh_opt->description =
	_("Minimum angle between two consecutive segments in Hermite method");

    degree_thresh_opt = G_define_option();
    degree_thresh_opt->key = "degree_thresh";
    degree_thresh_opt->type = TYPE_INTEGER;
    degree_thresh_opt->required = NO;
    degree_thresh_opt->answer = "0";
    degree_thresh_opt->description =
	_("Degree threshold in network generalization");

    closeness_thresh_opt = G_define_option();
    closeness_thresh_opt->key = "closeness_thresh";
    closeness_thresh_opt->type = TYPE_DOUBLE;
    closeness_thresh_opt->required = NO;
    closeness_thresh_opt->answer = "0";
    closeness_thresh_opt->options = "0-1";
    closeness_thresh_opt->description =
	_("Closeness threshold in network generalization");

    betweeness_thresh_opt = G_define_option();
    betweeness_thresh_opt->key = "betweeness_thresh";
    betweeness_thresh_opt->type = TYPE_DOUBLE;
    betweeness_thresh_opt->required = NO;
    betweeness_thresh_opt->answer = "0";
    betweeness_thresh_opt->description =
	_("Betweeness threshold in network generalization");

    alpha_opt = G_define_option();
    alpha_opt->key = "alpha";
    alpha_opt->type = TYPE_DOUBLE;
    alpha_opt->required = NO;
    alpha_opt->answer = "1.0";
    alpha_opt->description = _("Snakes alpha parameter");

    beta_opt = G_define_option();
    beta_opt->key = "beta";
    beta_opt->type = TYPE_DOUBLE;
    beta_opt->required = NO;
    beta_opt->answer = "1.0";
    beta_opt->description = _("Snakes beta parameter");

    iterations_opt = G_define_option();
    iterations_opt->key = "iterations";
    iterations_opt->type = TYPE_INTEGER;
    iterations_opt->required = NO;
    iterations_opt->answer = "1";
    iterations_opt->description = _("Number of iterations");

    cat_opt = G_define_standard_option(G_OPT_V_CATS);
    cat_opt->guisection = _("Selection");
    
    where_opt = G_define_standard_option(G_OPT_DB_WHERE);
    where_opt->guisection = _("Selection");

    loop_support_flag = G_define_flag();
    loop_support_flag->key = 'l';
    loop_support_flag->label = _("Disable loop support");
    loop_support_flag->description = _("Do not modify end points of lines forming a closed loop");

    notab_flag = G_define_standard_flag(G_FLG_V_TABLE);
    notab_flag->description = _("Do not copy attributes");
    notab_flag->guisection = _("Attributes");
    
    /* options and flags parser */
    if (G_parser(argc, argv))
	exit(EXIT_FAILURE);

    thresh = atof(thresh_opt->answer);
    look_ahead = atoi(look_ahead_opt->answer);
    alpha = atof(alpha_opt->answer);
    beta = atof(beta_opt->answer);
    reduction = atof(reduction_opt->answer);
    iterations = atoi(iterations_opt->answer);
    slide = atof(slide_opt->answer);
    angle_thresh = atof(angle_thresh_opt->answer);
    degree_thresh = atof(degree_thresh_opt->answer);
    closeness_thresh = atof(closeness_thresh_opt->answer);
    betweeness_thresh = atof(betweeness_thresh_opt->answer);

    mask_type = type_mask(type_opt);
    G_debug(3, "Method: %s", method_opt->answer);

    s = method_opt->answer;

    if (strcmp(s, "douglas") == 0)
	method = DOUGLAS;
    else if (strcmp(s, "lang") == 0)
	method = LANG;
    else if (strcmp(s, "reduction") == 0)
	method = VERTEX_REDUCTION;
    else if (strcmp(s, "reumann") == 0)
	method = REUMANN;
    else if (strcmp(s, "boyle") == 0)
	method = BOYLE;
    else if (strcmp(s, "distance_weighting") == 0)
	method = DISTANCE_WEIGHTING;
    else if (strcmp(s, "chaiken") == 0)
	method = CHAIKEN;
    else if (strcmp(s, "hermite") == 0)
	method = HERMITE;
    else if (strcmp(s, "snakes") == 0)
	method = SNAKES;
    else if (strcmp(s, "douglas_reduction") == 0)
	method = DOUGLAS_REDUCTION;
    else if (strcmp(s, "sliding_averaging") == 0)
	method = SLIDING_AVERAGING;
    else if (strcmp(s, "network") == 0)
	method = NETWORK;
    else if (strcmp(s, "displacement") == 0) {
	method = DISPLACEMENT;
	/* we can displace only the lines */
	mask_type = GV_LINE;
    }
    else {
	G_fatal_error(_("Unknown method"));
	exit(EXIT_FAILURE);
    }


    /* simplification or smoothing? */
    switch (method) {
    case DOUGLAS:
    case DOUGLAS_REDUCTION:
    case LANG:
    case VERTEX_REDUCTION:
    case REUMANN:
	simplification = 1;
	break;
    default:
	simplification = 0;
	break;
    }


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

    Vect_check_input_output_name(map_in->answer, map_out->answer,
				 G_FATAL_EXIT);

    Vect_set_open_level(2);

    if (Vect_open_old2(&In, map_in->answer, "", field_opt->answer) < 1)
	G_fatal_error(_("Unable to open vector map <%s>"), map_in->answer);

    if (Vect_get_num_primitives(&In, mask_type) == 0) {
	G_warning(_("No lines found in input map <%s>"), map_in->answer);
	Vect_close(&In);
	exit(EXIT_SUCCESS);
    }
    with_z = Vect_is_3d(&In);

    if (0 > Vect_open_new(&Out, map_out->answer, with_z)) {
	Vect_close(&In);
	G_fatal_error(_("Unable to create vector map <%s>"), map_out->answer);
    }

    if (error_out->answer) {
        if (0 > Vect_open_new(&Error, error_out->answer, with_z)) {
	    Vect_close(&In);
	    G_fatal_error(_("Unable to create error vector map <%s>"), error_out->answer);
        }
    }


    Vect_copy_head_data(&In, &Out);
    Vect_hist_copy(&In, &Out);
    Vect_hist_command(&Out);

    total_input = total_output = 0;

    layer = Vect_get_field_number(&In, field_opt->answer);
    /* parse filter options */
    if (layer > 0)
	cat_list = Vect_cats_set_constraint(&In, layer, 
			      where_opt->answer, cat_opt->answer);

    if (method == DISPLACEMENT) {
	/* modifies only lines, all other features including boundaries are preserved */
	/* options where, cats, and layer are respected */
	G_message(_("Displacement..."));
	snakes_displacement(&In, &Out, thresh, alpha, beta, 1.0, 10.0,
			    iterations, cat_list, layer);
    }

    /* TODO: rearrange code below. It's really messy */
    if (method == NETWORK) {
	/* extracts lines of selected type, all other features are discarded */
	/* options where, cats, and layer are ignored */
	G_message(_("Network generalization..."));
	total_output =
	    graph_generalization(&In, &Out, mask_type, degree_thresh, 
	                         closeness_thresh, betweeness_thresh);
    }

    /* copy tables here because method == NETWORK is complete and 
     * tables for Out may be needed for parse_filter_options() below */
    if (!notab_flag->answer) {
	if (method == NETWORK)
	    copy_tables_by_cats(&In, &Out);
	else
	    Vect_copy_tables(&In, &Out, -1);
    }
    else if (where_opt->answer && method < NETWORK) {
	G_warning(_("Attributes are needed for 'where' option, copying table"));
	Vect_copy_tables(&In, &Out, -1);
    }

    /* smoothing/simplification */
    if (method < NETWORK) {
	/* modifies only lines of selected type, all other features are preserved */
	int not_modified_boundaries = 0, n_oversimplified = 0;
	struct line_pnts *APoints;  /* original Points */

	set_topo_debug();

	Vect_copy_map_lines(&In, &Out);
	Vect_build_partial(&Out, GV_BUILD_CENTROIDS);

	G_message("-----------------------------------------------------");
	G_message(_("Generalization (%s)..."), method_opt->answer);
	G_message(_("Using threshold: %g %s"), thresh, G_database_unit_name(1));
	G_percent_reset();

	APoints = Vect_new_line_struct();

	n_lines = Vect_get_num_lines(&Out);
	for (i = 1; i <= n_lines; i++) {
	    int after = 0;

	    G_percent(i, n_lines, 1);

	    type = Vect_read_line(&Out, APoints, Cats, i);

	    if (!(type & GV_LINES) || !(mask_type & type))
		continue;

	    if (layer > 0) {
		if ((type & GV_LINE) &&
		    !Vect_cats_in_constraint(Cats, layer, cat_list))
		    continue;
		else if ((type & GV_BOUNDARY)) {
		    int do_line = 0;
		    int left, right;
		    
		    do_line = Vect_cats_in_constraint(Cats, layer, cat_list);

		    if (!do_line) {
			
			/* check if any of the centroids is selected */
			Vect_get_line_areas(&Out, i, &left, &right);
			if (left < 0)
			    left = Vect_get_isle_area(&Out, abs(left));
			if (right < 0)
			    right = Vect_get_isle_area(&Out, abs(right));

			if (left > 0) {
			    Vect_get_area_cats(&Out, left, Cats);
			    do_line = Vect_cats_in_constraint(Cats, layer, cat_list);
			}
			
			if (!do_line && right > 0) {
			    Vect_get_area_cats(&Out, right, Cats);
			    do_line = Vect_cats_in_constraint(Cats, layer, cat_list);
			}
		    }
		    if (!do_line)
			continue;
		}
	    }

	    Vect_line_prune(APoints);

	    if (APoints->n_points < 2)
		/* Line of length zero, delete if boundary ? */
		continue;

	    total_input += APoints->n_points;

	    /* copy points */
	    Vect_reset_line(Points);
	    Vect_append_points(Points, APoints, GV_FORWARD);
	    
	    loop_support = 0;
	    if (!loop_support_flag->answer) {
		int n1, n2;

		Vect_get_line_nodes(&Out, i, &n1, &n2);
		if (n1 == n2) {
		    if (Vect_get_node_n_lines(&Out, n1) == 2) {
			if (abs(Vect_get_node_line(&Out, n1, 0)) == i &&
			    abs(Vect_get_node_line(&Out, n1, 1)) == i)
			    loop_support = 1;
		    }
		}
	    }
		
	    for (iter = 0; iter < iterations; iter++) {
		switch (method) {
		case DOUGLAS:
		    douglas_peucker(Points, thresh, with_z);
		    break;
		case DOUGLAS_REDUCTION:
		    douglas_peucker_reduction(Points, thresh, reduction,
					      with_z);
		    break;
		case LANG:
		    lang(Points, thresh, look_ahead, with_z);
		    break;
		case VERTEX_REDUCTION:
		    vertex_reduction(Points, thresh, with_z);
		    break;
		case REUMANN:
		    reumann_witkam(Points, thresh, with_z);
		    break;
		case BOYLE:
		    boyle(Points, look_ahead, loop_support, with_z);
		    break;
		case SLIDING_AVERAGING:
		    sliding_averaging(Points, slide, look_ahead, loop_support, with_z);
		    break;
		case DISTANCE_WEIGHTING:
		    distance_weighting(Points, slide, look_ahead, loop_support, with_z);
		    break;
		case CHAIKEN:
		    chaiken(Points, thresh, loop_support, with_z);
		    break;
		case HERMITE:
		    hermite(Points, thresh, angle_thresh, loop_support, with_z);
		    break;
		case SNAKES:
		    snakes(Points, alpha, beta, loop_support, with_z);
		    break;
		}
	    }

	    if (loop_support == 0) { 
		/* safety check, BUG in method if not passed */
		if (APoints->x[0] != Points->x[0] || 
		    APoints->y[0] != Points->y[0] ||
		    APoints->z[0] != Points->z[0])
		    G_fatal_error(_("Method '%s' did not preserve first point"), method_opt->answer);
		    
		if (APoints->x[APoints->n_points - 1] != Points->x[Points->n_points - 1] || 
		    APoints->y[APoints->n_points - 1] != Points->y[Points->n_points - 1] ||
		    APoints->z[APoints->n_points - 1] != Points->z[Points->n_points - 1])
		    G_fatal_error(_("Method '%s' did not preserve last point"), method_opt->answer);
	    }
	    else {
		/* safety check, BUG in method if not passed */
		if (Points->x[0] != Points->x[Points->n_points - 1] || 
		    Points->y[0] != Points->y[Points->n_points - 1] ||
		    Points->z[0] != Points->z[Points->n_points - 1])
		    G_fatal_error(_("Method '%s' did not preserve loop"), method_opt->answer);
	    }

	    Vect_line_prune(Points);

	    /* oversimplified line */
	    if (Points->n_points < 2) {
		after = APoints->n_points;
		n_oversimplified++;
                if (error_out->answer)
		    Vect_write_line(&Error, type, APoints, Cats);
	    }
	    /* check for topology corruption */
	    else if (type == GV_BOUNDARY) {
		if (!check_topo(&Out, i, APoints, Points, Cats)) {
		    after = APoints->n_points;
		    not_modified_boundaries++;
                    if (error_out->answer)
		        Vect_write_line(&Error, type, APoints, Cats);
		}
		else
		    after = Points->n_points;
	    }
	    else {
		/* type == GV_LINE */
		Vect_rewrite_line(&Out, i, type, Points, Cats);
		after = Points->n_points;
	    }

	    total_output += after;
	}
	if (not_modified_boundaries > 0)
	    G_warning(_("%d boundaries were not modified because modification would damage topology"),
		      not_modified_boundaries);
	if (n_oversimplified > 0)
	    G_warning(_("%d lines/boundaries were not modified due to over-simplification"),
		      n_oversimplified);
	G_message("-----------------------------------------------------");

	/* make sure that clean topo is built at the end */
	Vect_build_partial(&Out, GV_BUILD_NONE);
        if (error_out->answer)
	    Vect_build_partial(&Error, GV_BUILD_NONE);
    }

    Vect_build(&Out);
    if (error_out->answer)
        Vect_build(&Error);

    Vect_close(&In);
    Vect_close(&Out);
    if (error_out->answer)
        Vect_close(&Error);

    G_message("-----------------------------------------------------");
    if (total_input != 0 && total_input != total_output)
	G_done_msg(_("Number of vertices for selected features %s from %d to %d (%d%% remaining)"),
                   simplification ? _("reduced") : _("changed"), 
                   total_input, total_output,
                   (total_output * 100) / total_input);
    else
        G_done_msg(" ");

    exit(EXIT_SUCCESS);
}
Beispiel #8
0
int display_shape(struct Map_info *Map, int type, struct cat_list *Clist, const struct Cell_head *window, 
		  const struct color_rgb *bcolor, const struct color_rgb *fcolor, int chcat,
		  const char *icon, double size, const char *size_column, int sqrt_flag, const char *rot_column, /* lines only */
		  int id_flag, int cats_colors_flag, char *rgb_column,
		  int default_width, char *width_column, double width_scale,
		  char *z_style)
{
    int open_db, field, i, stat;
    dbCatValArray cvarr_rgb, cvarr_width, cvarr_size, cvarr_rot;
    struct field_info *fi;
    dbDriver *driver;
    int nrec_rgb, nrec_width, nrec_size, nrec_rot, have_colors;
    struct Colors colors, zcolors;
    struct bound_box box;
    
    stat = 0;
    nrec_rgb = nrec_width = nrec_size = nrec_rot = 0;
    
    open_db = rgb_column || width_column || size_column || rot_column;
    if (open_db) {
	field = Clist->field > 0 ? Clist->field : 1;
	fi = Vect_get_field(Map, field);
	if (!fi) {
	    G_fatal_error(_("Database connection not defined for layer %d"),
			  field);
	}
	
	driver = db_start_driver_open_database(fi->driver, fi->database);
	if (!driver)
	    G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
			  fi->database, fi->driver);
        db_set_error_handler_driver(driver);
    }
    
    /* fisrt search for color table */
    have_colors = Vect_read_colors(Vect_get_name(Map), Vect_get_mapset(Map),
				   &colors);
    if (have_colors && rgb_column) {
        G_warning(_("Both color table and <%s> option detected. "
                    "Color table will ignored."), "rgb_column");
        have_colors = FALSE;
    }

    if (rgb_column) {
	/* read RRR:GGG:BBB color strings from table */
	db_CatValArray_init(&cvarr_rgb);
	
	nrec_rgb = db_select_CatValArray(driver, fi->table, fi->key,
					 rgb_column, NULL, &cvarr_rgb);
	
	G_debug(3, "nrec_rgb (%s) = %d", rgb_column, nrec_rgb);
	    
	if (cvarr_rgb.ctype != DB_C_TYPE_STRING) {
	    G_warning(_("Color definition column ('%s') not a string. "
			"Column must be of form 'RRR:GGG:BBB' where RGB values range 0-255. "
			"You can use '%s' module to define color rules. "
			"Unable to colorize features."),
		      rgb_column, "v.colors");
            rgb_column = NULL;
        }
	else {
	    if (nrec_rgb < 0)
		G_fatal_error(_("Unable to select data ('%s') from table"),
			      rgb_column);
	    
	    G_debug(2, "\n%d records selected from table", nrec_rgb);
	}
    }
    if (width_column) {
	if (*width_column == '\0')
	    G_fatal_error(_("Line width column not specified"));

	db_CatValArray_init(&cvarr_width);

	nrec_width = db_select_CatValArray(driver, fi->table, fi->key,
					   width_column, NULL, &cvarr_width);

	G_debug(3, "nrec_width (%s) = %d", width_column, nrec_width);

	if (cvarr_width.ctype != DB_C_TYPE_INT &&
	    cvarr_width.ctype != DB_C_TYPE_DOUBLE)
	    G_fatal_error(_("Line width column ('%s') not a number"),
			  width_column);

	if (nrec_width < 0)
	    G_fatal_error(_("Unable to select data ('%s') from table"),
			  width_column);

	G_debug(2, "\n%d records selected from table", nrec_width);

	for (i = 0; i < cvarr_width.n_values; i++) {
	    G_debug(4, "cat = %d  %s = %d", cvarr_width.value[i].cat,
		    width_column,
		    (cvarr_width.ctype ==
		     DB_C_TYPE_INT ? cvarr_width.value[i].val.
		     i : (int)cvarr_width.value[i].val.d));
	}
    }

    if (size_column) {
	if (*size_column == '\0')
	    G_fatal_error(_("Symbol size column not specified"));
	
	db_CatValArray_init(&cvarr_size);

	nrec_size = db_select_CatValArray(driver, fi->table, fi->key,
					  size_column, NULL, &cvarr_size);
	
	G_debug(3, "nrec_size (%s) = %d", size_column, nrec_size);

	if (cvarr_size.ctype != DB_C_TYPE_INT &&
	    cvarr_size.ctype != DB_C_TYPE_DOUBLE)
	    G_fatal_error(_("Symbol size column ('%s') is not numeric"),
			  size_column);

	if (nrec_size < 0)
	    G_fatal_error(_("Unable to select data ('%s') from table"),
			  size_column);

	G_debug(2, " %d records selected from table", nrec_size);

	for (i = 0; i < cvarr_size.n_values; i++) {
	    G_debug(4, "(size) cat = %d  %s = %.2f", cvarr_size.value[i].cat,
		    size_column,
		    (cvarr_size.ctype ==
		     DB_C_TYPE_INT ? (double)cvarr_size.value[i].val.i
		     : cvarr_size.value[i].val.d));
	}
    }

    if (rot_column) {
	if (*rot_column == '\0')
	    G_fatal_error(_("Symbol rotation column not specified"));

	db_CatValArray_init(&cvarr_rot);

	nrec_rot = db_select_CatValArray(driver, fi->table, fi->key,
					 rot_column, NULL, &cvarr_rot);

	G_debug(3, "nrec_rot (%s) = %d", rot_column, nrec_rot);

	if (cvarr_rot.ctype != DB_C_TYPE_INT &&
	    cvarr_rot.ctype != DB_C_TYPE_DOUBLE)
	    G_fatal_error(_("Symbol rotation column ('%s') is not numeric"),
			  rot_column);

	if (nrec_rot < 0)
	    G_fatal_error(_("Unable to select data ('%s') from table"),
			  rot_column);

	G_debug(2, " %d records selected from table", nrec_rot);

	for (i = 0; i < cvarr_rot.n_values; i++) {
	    G_debug(4, "(rot) cat = %d  %s = %.2f", cvarr_rot.value[i].cat,
		    rot_column,
		    (cvarr_rot.ctype ==
		     DB_C_TYPE_INT ? (double)cvarr_rot.value[i].val.i
		     : cvarr_rot.value[i].val.d));
	}
    }

    if (open_db) {
	db_close_database_shutdown_driver(driver);
    }

    if (z_style) {
	if (!Vect_is_3d(Map)) {
	    G_warning(_("Vector map is not 3D. Unable to colorize features based on z-coordinates."));
	    z_style = NULL;
	}
        else if (rgb_column) {
            G_warning(_("%s= and %s= are mutually exclusive. "
                        "%s= will be ignored."), "zcolor", "rgb_column", "zcolor");
	    z_style = NULL;
        }
	else {
	    Vect_get_map_box(Map, &box);
	    Rast_make_fp_colors(&zcolors, z_style, box.B, box.T);
	}
    }

    stat = 0;
    if (type & GV_AREA && Vect_get_num_primitives(Map, GV_CENTROID | GV_BOUNDARY) > 0)
	stat += display_area(Map, Clist, window, 
			     bcolor, fcolor, chcat,
			     id_flag, cats_colors_flag,
			     default_width, width_scale,
			     z_style ? &zcolors : NULL,
			     rgb_column ? &cvarr_rgb : NULL,
			     have_colors ? &colors : NULL,
			     &cvarr_width, nrec_width);
    
    stat += display_lines(Map, type, Clist,
			  bcolor, fcolor, chcat,
			  icon, size, sqrt_flag,
			  id_flag, cats_colors_flag,
			  default_width, width_scale,
			  z_style ? &zcolors : NULL,
			  rgb_column ? &cvarr_rgb : NULL,
			  have_colors ? &colors : NULL,
			  &cvarr_width, nrec_width,
			  &cvarr_size, nrec_size,
			  &cvarr_rot, nrec_rot);
    
    return stat;
}
Beispiel #9
0
int main(int argc, char *argv[])
{
    int i, j, precision, field, type, nlines;
    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();

    if (type_opt->answer[0] == 'l') {
        type = TYPE_LINE;
    }
    else {
        if (type_opt->answer[2] == 'l')
            type = TYPE_POLY;
        else
            type = TYPE_POINT;
    }
            
    /* 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);
    if (Vect_open_old2(&In, in_opt->answer, "", field_opt->answer) < 0)
	G_fatal_error(_("Unable to open vector map <%s>"), in_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);

    nlines = Vect_get_num_lines(&In);
    
    /* extract areas if any or requested */
    if (type == TYPE_POLY) {
	if (Vect_get_num_areas(&In) == 0) {
	    G_warning(_("No areas found, skipping %s"), "type=poly");
	}
	else {
            int nareas;
            
            nareas = Vect_get_num_areas(&In);
	    /* 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 <= nareas; i++) {
		G_percent(i, nareas, 5);

		/* skip areas without centroid */
		if (Vect_get_area_centroid(&In, i) == 0) {
		    G_warning(_("Skipping area %d without centroid"), i);
		    continue;
		}

		/* 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(_("%d areas extracted"), cnt);
	}
    }
    
    /* extract points if requested */
    if (type == TYPE_POINT) {
	if (Vect_get_num_primitives(&In, GV_POINTS) == 0) {
	    G_warning(_("No points found, skipping %s"), "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 <= nlines; i++) {
		G_percent(i, nlines, 5);
                
		if (!(Vect_read_line(&In, Points, Cats, i) & GV_POINTS))
                    continue;
                
		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(_("%d points extracted"), cnt);
	}
    }
    
    /* extract lines if requested */
    if (type == TYPE_LINE) {
	if (Vect_get_num_primitives(&In, GV_LINES) == 0) {
	    G_warning(_("No lines found, skipping %s"), "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 <= nlines; i++) {
		G_percent(i, nlines, 5);
                
		if (!(Vect_read_line(&In, Points, Cats, i) & GV_LINES))
                    continue;
                
                if (field != -1 && !Vect_cat_get(Cats, field, NULL))
		    continue;
                
		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(_("%d lines extracted"), 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);
    
    exit(EXIT_SUCCESS);
}
Beispiel #10
0
void print_info(const struct Map_info *Map)
{
    int i;
    char line[100];
    char tmp1[100], tmp2[100];

    struct bound_box box;
    
    divider('+');
    if (Vect_maptype(Map) & (GV_FORMAT_OGR | GV_FORMAT_OGR_DIRECT)) {
	/* for OGR format print also datasource and layer */
	sprintf(line, "%-17s%s", _("OGR layer:"),
		Vect_get_ogr_layer_name(Map));
	printline(line);
	sprintf(line, "%-17s%s", _("OGR datasource:"),
		Vect_get_ogr_dsn_name(Map));
	printline(line);
    }
    else {
	sprintf(line, "%-17s%s", _("Name:"),
		Vect_get_name(Map));
	printline(line);
	sprintf(line, "%-17s%s", _("Mapset:"),
		Vect_get_mapset(Map));
	printline(line);
    }

    sprintf(line, "%-17s%s", _("Location:"),
	    G_location());
    printline(line);
    sprintf(line, "%-17s%s", _("Database:"),
	    G_gisdbase());
    printline(line);
    sprintf(line, "%-17s%s", _("Title:"),
	    Vect_get_map_name(Map));
    printline(line);
    sprintf(line, "%-17s1:%d", _("Map scale:"),
	    Vect_get_scale(Map));
    printline(line);
    
    if (Vect_maptype(Map) & (GV_FORMAT_OGR | GV_FORMAT_OGR_DIRECT)) {
	sprintf(line, "%-17s%s (%s)", _("Map format:"),
		Vect_maptype_info(Map), Vect_get_ogr_format_info(Map));
    }
    else {
	sprintf(line, "%-17s%s", _("Map format:"),
		Vect_maptype_info(Map));
    }
    
    printline(line);
    sprintf(line, "%-17s%s", _("Name of creator:"),
	    Vect_get_person(Map));
    printline(line);
    sprintf(line, "%-17s%s", _("Organization:"),
	    Vect_get_organization(Map));
    printline(line);
    sprintf(line, "%-17s%s", _("Source date:"),
	    Vect_get_map_date(Map));
    printline(line);
    
    divider('|');
    
    sprintf(line, "  %s: %s (%s: %i)",
	    _("Type of map"), _("vector"), _("level"), Vect_level(Map));
    
    printline(line);
    
    if (Vect_level(Map) > 0) {
	printline("");
	sprintf(line,
		"  %-24s%-9d       %-22s%-9d",
		_("Number of points:"), 
		Vect_get_num_primitives(Map, GV_POINT),
		_("Number of centroids:"),
		Vect_get_num_primitives(Map, GV_CENTROID));
	printline(line);
	sprintf(line,
		"  %-24s%-9d       %-22s%-9d",
		_("Number of lines:"),
		Vect_get_num_primitives(Map, GV_LINE),
		_("Number of boundaries:"),
		Vect_get_num_primitives(Map, GV_BOUNDARY));
	printline(line);
	sprintf(line,
		"  %-24s%-9d       %-22s%-9d",
		_("Number of areas:"),
		Vect_get_num_areas(Map),
		_("Number of islands:"),
		Vect_get_num_islands(Map));
	printline(line);
	if (Vect_is_3d(Map)) {
	    sprintf(line,
		    "  %-24s%-9d       %-22s%-9d",
		    _("Number of faces:"),
		    Vect_get_num_primitives(Map, GV_FACE),
		    _("Number of kernels:"),
		    Vect_get_num_primitives(Map, GV_KERNEL));
	    printline(line);
	    sprintf(line,
		    "  %-24s%-9d       %-22s%-9d",
		    _("Number of volumes:"),
		    Vect_get_num_volumes(Map),
		    _("Number of holes:"),
		    Vect_get_num_holes(Map));
	    printline(line);
	}
	printline("");
	
	sprintf(line, "  %-24s%s",
		_("Map is 3D:"),
		Vect_is_3d(Map) ? _("Yes") : _("No"));
	printline(line);
	sprintf(line, "  %-24s%-9d",
		_("Number of dblinks:"),
		Vect_get_num_dblinks(Map));
	printline(line);
    }
    
    printline("");
    /* this differs from r.info in that proj info IS taken from the map here, not the location settings */
    /* Vect_get_proj_name() and _zone() are typically unset?! */
    if (G_projection() == PROJECTION_UTM)
	sprintf(line, "  %s: %s (%s %d)",
		_("Projection:"),
		Vect_get_proj_name(Map),
		_("zone"), Vect_get_zone(Map));
    else
	sprintf(line, "  %s: %s",
		_("Projection"),
		Vect_get_proj_name(Map));
    
    printline(line);
    printline("");
    
    Vect_get_map_box(Map, &box);
    
    G_format_northing(box.N, tmp1, G_projection());
    G_format_northing(box.S, tmp2, G_projection());
    sprintf(line, "              %c: %17s    %c: %17s",
	    'N', tmp1, 'S', tmp2);
    printline(line);
    
    G_format_easting(box.E, tmp1, G_projection());
    G_format_easting(box.W, tmp2, G_projection());
    sprintf(line, "              %c: %17s    %c: %17s",
	    'E', tmp1, 'W', tmp2);
    printline(line);
    
    if (Vect_is_3d(Map)) {
	format_double(box.B, tmp1);
	format_double(box.T, tmp2);
	sprintf(line, "              %c: %17s    %c: %17s",
		'B', tmp1, 'T', tmp2);
	printline(line);
    }
    printline("");

    format_double(Vect_get_thresh(Map), tmp1);
    sprintf(line, "  %s: %s", _("Digitization threshold"), tmp1);
    printline(line);
    sprintf(line, "  %s:", _("Comment"));
    printline(line);
    sprintf(line, "    %s", Vect_get_comment(Map));
    printline(line);
    divider('+');
    fprintf(stdout, "\n");
}
Beispiel #11
0
void print_topo(const struct Map_info *Map)
{
    int with_z;
    long nprimitives;

    nprimitives = 0;
    with_z = Vect_is_3d(Map);

    nprimitives += Vect_get_num_primitives(Map, GV_POINT);
    nprimitives += Vect_get_num_primitives(Map, GV_LINE);
    nprimitives += Vect_get_num_primitives(Map, GV_BOUNDARY);
    nprimitives += Vect_get_num_primitives(Map, GV_CENTROID);

    if (with_z) {
	nprimitives += Vect_get_num_primitives(Map, GV_FACE);
	nprimitives += Vect_get_num_primitives(Map, GV_KERNEL);
    }
    

    fprintf(stdout, "nodes=%d\n",
	    Vect_get_num_nodes(Map));
    fflush(stdout);

    fprintf(stdout, "points=%d\n",
	    Vect_get_num_primitives(Map, GV_POINT));
    fflush(stdout);
    
    fprintf(stdout, "lines=%d\n",
	    Vect_get_num_primitives(Map, GV_LINE));
    fflush(stdout);
    
    fprintf(stdout, "boundaries=%d\n",
	    Vect_get_num_primitives(Map, GV_BOUNDARY));
    fflush(stdout);
    
    fprintf(stdout, "centroids=%d\n",
	    Vect_get_num_primitives(Map, GV_CENTROID));
    fflush(stdout);
    
    fprintf(stdout, "areas=%d\n", Vect_get_num_areas(Map));
    fflush(stdout);
    
    fprintf(stdout, "islands=%d\n",
	    Vect_get_num_islands(Map));
    fflush(stdout);
    
    if (with_z) {
	fprintf(stdout, "faces=%d\n",
		Vect_get_num_primitives(Map, GV_FACE));
	fflush(stdout);
	
	fprintf(stdout, "kernels=%d\n",
		Vect_get_num_primitives(Map, GV_KERNEL));
	fflush(stdout);
	
	fprintf(stdout, "volumes=%d\n",
		Vect_get_num_primitives(Map, GV_VOLUME));
	fflush(stdout);
	
	fprintf(stdout, "holes=%d\n",
		Vect_get_num_holes(Map));
	fflush(stdout);
    }

    fprintf(stdout, "primitives=%ld\n", nprimitives);
    fflush(stdout);

    fprintf(stdout, "map3d=%d\n",
	    Vect_is_3d(Map) ? 1 : 0);
    fflush(stdout);
}
Beispiel #12
0
void print_info(const struct Map_info *Map)
{
    int i, map_type;
    char line[1024];
    char timebuff[256];
    struct TimeStamp ts;
    int time_ok, first_time_ok, second_time_ok;
    struct bound_box box;
    char tmp1[1024], tmp2[1024];
    
    time_ok = first_time_ok = second_time_ok = FALSE;
    map_type = Vect_maptype(Map);
    
    /* Check the Timestamp */
    time_ok = G_read_vector_timestamp(Vect_get_name(Map), NULL, "", &ts);

    /* Check for valid entries, show none if no timestamp available */
    if (time_ok == TRUE) {
        if (ts.count > 0)
            first_time_ok = TRUE;
        if (ts.count > 1)
            second_time_ok = TRUE;
    }

    divider('+');
    sprintf(line, "%-17s%s", _("Name:"),
            Vect_get_name(Map));
    printline(line);
    sprintf(line, "%-17s%s", _("Mapset:"),
            Vect_get_mapset(Map));
    printline(line);
    
    sprintf(line, "%-17s%s", _("Location:"),
            G_location());
    printline(line);
    sprintf(line, "%-17s%s", _("Database:"),
            G_gisdbase());
    printline(line);

    sprintf(line, "%-17s%s", _("Title:"),
            Vect_get_map_name(Map));
    printline(line);
    sprintf(line, "%-17s1:%d", _("Map scale:"),
            Vect_get_scale(Map));
    printline(line);

    sprintf(line, "%-17s%s", _("Name of creator:"),
            Vect_get_person(Map));
    printline(line);
    sprintf(line, "%-17s%s", _("Organization:"),
            Vect_get_organization(Map));
    printline(line);
    sprintf(line, "%-17s%s", _("Source date:"),
            Vect_get_map_date(Map));
    printline(line);

    /* This shows the TimeStamp (if present) */
    if (time_ok  == TRUE && (first_time_ok || second_time_ok)) {
        G_format_timestamp(&ts, timebuff);
        sprintf(line, "%-17s%s", _("Timestamp (first layer): "), timebuff);
        printline(line);
    }
    else {
        strcpy(line, _("Timestamp (first layer): none"));
        printline(line);
    }
    
    divider('|');
    
    if (map_type == GV_FORMAT_OGR ||
        map_type == GV_FORMAT_OGR_DIRECT) {
        sprintf(line, "%-17s%s (%s)", _("Map format:"),
                Vect_maptype_info(Map), Vect_get_finfo_format_info(Map));
        printline(line);
        
        /* for OGR format print also datasource and layer */
        sprintf(line, "%-17s%s", _("OGR layer:"),
                Vect_get_finfo_layer_name(Map));
        printline(line);
        sprintf(line, "%-17s%s", _("OGR datasource:"),
                Vect_get_finfo_dsn_name(Map));
        printline(line);
        sprintf(line, "%-17s%s", _("Feature type:"),
                Vect_get_finfo_geometry_type(Map));
        printline(line);
    }
    else if (map_type == GV_FORMAT_POSTGIS) {
        int topo_format;
        char *toposchema_name, *topogeom_column;
        int topo_geo_only;

        const struct Format_info *finfo;

        finfo = Vect_get_finfo(Map);
        
        sprintf(line, "%-17s%s (%s)", _("Map format:"),
                Vect_maptype_info(Map), Vect_get_finfo_format_info(Map));
        printline(line);
        
        /* for PostGIS format print also datasource and layer */
        sprintf(line, "%-17s%s", _("DB table:"),
                Vect_get_finfo_layer_name(Map));
        printline(line);
        sprintf(line, "%-17s%s", _("DB name:"),
                Vect_get_finfo_dsn_name(Map));
        printline(line);

        sprintf(line, "%-17s%s", _("Geometry column:"),
                finfo->pg.geom_column);
        printline(line);

        sprintf(line, "%-17s%s", _("Feature type:"),
                Vect_get_finfo_geometry_type(Map));
        printline(line);


        
        topo_format = Vect_get_finfo_topology_info(Map,
                                                   &toposchema_name, &topogeom_column,
                                                   &topo_geo_only);
        if (topo_format == GV_TOPO_POSTGIS) {
            sprintf(line, "%-17s%s (%s %s%s)", _("Topology:"), "PostGIS",
                    _("schema:"), toposchema_name,
                    topo_geo_only ? ", topo-geo-only: yes" : "");
            printline(line);

            sprintf(line, "%-17s%s", _("Topology column:"),
                    topogeom_column);
        }
        else
            sprintf(line, "%-17s%s", _("Topology:"), "pseudo (simple features)");
        
        printline(line);
    }
    else {
        sprintf(line, "%-17s%s", _("Map format:"),
                Vect_maptype_info(Map));
        printline(line);
    }
    

    divider('|');
    
    sprintf(line, "  %s: %s (%s: %i)",
            _("Type of map"), _("vector"), _("level"), Vect_level(Map));
    printline(line);
    
    if (Vect_level(Map) > 0) {
        printline("");
        sprintf(line,
                "  %-24s%-9d       %-22s%-9d",
                _("Number of points:"), 
                Vect_get_num_primitives(Map, GV_POINT),
                _("Number of centroids:"),
                Vect_get_num_primitives(Map, GV_CENTROID));
        printline(line);
        sprintf(line,
                "  %-24s%-9d       %-22s%-9d",
                _("Number of lines:"),
                Vect_get_num_primitives(Map, GV_LINE),
                _("Number of boundaries:"),
                Vect_get_num_primitives(Map, GV_BOUNDARY));
        printline(line);
        sprintf(line,
                "  %-24s%-9d       %-22s%-9d",
                _("Number of areas:"),
                Vect_get_num_areas(Map),
                _("Number of islands:"),
                Vect_get_num_islands(Map));
        printline(line);
        if (Vect_is_3d(Map)) {
            sprintf(line,
                    "  %-24s%-9d       %-22s%-9d",
                    _("Number of faces:"),
                    Vect_get_num_primitives(Map, GV_FACE),
                    _("Number of kernels:"),
                    Vect_get_num_primitives(Map, GV_KERNEL));
            printline(line);
            sprintf(line,
                    "  %-24s%-9d       %-22s%-9d",
                    _("Number of volumes:"),
                    Vect_get_num_volumes(Map),
                    _("Number of holes:"),
                    Vect_get_num_holes(Map));
            printline(line);
        }
        printline("");

        sprintf(line, "  %-24s%s",
                _("Map is 3D:"),
                Vect_is_3d(Map) ? _("Yes") : _("No"));
        printline(line);
        sprintf(line, "  %-24s%-9d",
                _("Number of dblinks:"),
                Vect_get_num_dblinks(Map));
        printline(line);
    }

    printline("");
    /* this differs from r.info in that proj info IS taken from the map here, not the location settings */
    /* Vect_get_proj_name() and _zone() are typically unset?! */
    if (G_projection() == PROJECTION_UTM) {
        int utm_zone;

        utm_zone = Vect_get_zone(Map);
        if (utm_zone < 0 || utm_zone > 60)
            strcpy(tmp1, _("invalid"));
        else if (utm_zone == 0)
            strcpy(tmp1, _("unspecified"));
        else
            sprintf(tmp1, "%d", utm_zone);

        sprintf(line, "  %s: %s (%s %s)",
                _("Projection"), Vect_get_proj_name(Map),
                _("zone"), tmp1);
    }
    else
        sprintf(line, "  %s: %s",
                _("Projection"), Vect_get_proj_name(Map));

    printline(line);
    printline("");

    Vect_get_map_box(Map, &box);

    G_format_northing(box.N, tmp1, G_projection());
    G_format_northing(box.S, tmp2, G_projection());
    sprintf(line, "              %c: %17s    %c: %17s",
            'N', tmp1, 'S', tmp2);
    printline(line);
    
    G_format_easting(box.E, tmp1, G_projection());
    G_format_easting(box.W, tmp2, G_projection());
    sprintf(line, "              %c: %17s    %c: %17s",
            'E', tmp1, 'W', tmp2);
    printline(line);
    
    if (Vect_is_3d(Map)) {
        format_double(box.B, tmp1);
        format_double(box.T, tmp2);
        sprintf(line, "              %c: %17s    %c: %17s",
                'B', tmp1, 'T', tmp2);
        printline(line);
    }
    printline("");

    format_double(Vect_get_thresh(Map), tmp1);
    sprintf(line, "  %s: %s", _("Digitization threshold"), tmp1);
    printline(line);
    sprintf(line, "  %s:", _("Comment"));
    printline(line);
    sprintf(line, "    %s", Vect_get_comment(Map));
    printline(line);
    divider('+');
    fprintf(stdout, "\n");
}
Beispiel #13
0
int main(int argc, char **argv)
{
    int field, type, vertex_type;
    double dmax;
    char buf[DB_SQL_MAX];

    struct {
        struct Option *input, *output, *type, *dmax, *lfield, *use;
    } opt;
    struct {
        struct Flag *table, *inter;
    } flag;
    struct GModule *module;
    struct Map_info In, Out;
    struct line_cats *LCats;
    struct line_pnts *LPoints;

    dbDriver *driver;
    struct field_info *Fi;

    dbString stmt;

    G_gisinit(argv[0]);

    module = G_define_module();
    G_add_keyword(_("vector"));
    G_add_keyword(_("geometry"));
    G_add_keyword("3D");
    G_add_keyword(_("node"));
    G_add_keyword(_("vertex"));
    module->description =
	_("Creates points along input lines in new vector map with 2 layers.");

    opt.input = G_define_standard_option(G_OPT_V_INPUT);

    opt.lfield = G_define_standard_option(G_OPT_V_FIELD);
    opt.lfield->key = "llayer";
    opt.lfield->answer = "1";
    opt.lfield->label = "Line layer number or name";
    opt.lfield->guisection = _("Selection");

    opt.type = G_define_standard_option(G_OPT_V3_TYPE);
    opt.type->answer = "point,line,boundary,centroid,face";
    opt.type->guisection = _("Selection");

    opt.output = G_define_standard_option(G_OPT_V_OUTPUT);

    opt.use = G_define_option();
    opt.use->key = "use";
    opt.use->type = TYPE_STRING;
    opt.use->required = NO;
    opt.use->description = _("Use line nodes or vertices only");
    opt.use->options = "node,vertex";

    opt.dmax = G_define_option();
    opt.dmax->key = "dmax";
    opt.dmax->type = TYPE_DOUBLE;
    opt.dmax->required = NO;
    opt.dmax->answer = "100";
    opt.dmax->description = _("Maximum distance between points in map units");

    flag.inter = G_define_flag();
    flag.inter->key = 'i';
    flag.inter->description = _("Interpolate points between line vertices (only for use=vertex)");
    

    flag.table = G_define_standard_flag(G_FLG_V_TABLE);

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

    LCats = Vect_new_cats_struct();
    LPoints = Vect_new_line_struct();
    db_init_string(&stmt);

    type = Vect_option_to_types(opt.type);
    dmax = atof(opt.dmax->answer);

    vertex_type = 0;
    if (opt.use->answer) {
        if (opt.use->answer[0] == 'n')
            vertex_type = GV_NODE;
        else
            vertex_type = GV_VERTEX;
    }
    
    Vect_check_input_output_name(opt.input->answer, opt.output->answer,
				 G_FATAL_EXIT);

    /* Open input lines */
    Vect_set_open_level(2);

    if (Vect_open_old2(&In, opt.input->answer, "", opt.lfield->answer) < 0)
	G_fatal_error(_("Unable to open vector map <%s>"), opt.input->answer);

    Vect_set_error_handler_io(&In, &Out);
    
    field = Vect_get_field_number(&In, opt.lfield->answer);
    
    /* Open output segments */
    if (Vect_open_new(&Out, opt.output->answer, Vect_is_3d(&In)) < 0)
	G_fatal_error(_("Unable to create vector map <%s>"),
			opt.output->answer);

    Vect_copy_head_data(&In, &Out);
    Vect_hist_copy(&In, &Out);
    Vect_hist_command(&Out);

    /* Table */
    Fi = NULL;
    if (!flag.table->answer) {
	struct field_info *Fin;

	/* copy input table */
	Fin = Vect_get_field(&In, field);
	if (Fin) {		/* table defined */
	    int ret;

	    Fi = Vect_default_field_info(&Out, 1, NULL, GV_MTABLE);
	    Vect_map_add_dblink(&Out, 1, NULL, Fi->table, Fin->key,
				Fi->database, Fi->driver);

	    ret = db_copy_table(Fin->driver, Fin->database, Fin->table,
				Fi->driver, Vect_subst_var(Fi->database,
							   &Out), Fi->table);

	    if (ret == DB_FAILED) {
		G_fatal_error(_("Unable to copy table <%s>"),
			      Fin->table);
	    }
	}

	Fi = Vect_default_field_info(&Out, 2, NULL, GV_MTABLE);
	Vect_map_add_dblink(&Out, 2, NULL, Fi->table, GV_KEY_COLUMN, Fi->database,
			    Fi->driver);

	/* Open driver */
	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);

	if (field == -1) 
            sprintf(buf,
                "create table %s ( cat int, along double precision )",
                Fi->table);
         else
            sprintf(buf,
		"create table %s ( cat int, lcat int, along double precision )",
		Fi->table);
	db_append_string(&stmt, buf);

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

	if (db_create_index2(driver, Fi->table, GV_KEY_COLUMN) != DB_OK)
	    G_warning(_("Unable to create index for table <%s>, key <%s>"),
		      Fi->table, GV_KEY_COLUMN);

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

	db_begin_transaction(driver);
    }

    if (type & (GV_POINTS | GV_LINES | GV_FACE)) {
        int line, nlines, nskipped;

        nskipped = 0;
	nlines = Vect_get_num_lines(&In);
	for (line = 1; line <= nlines; line++) {
	    int ltype, cat;

	    G_debug(3, "line = %d", line);
	    G_percent(line, nlines, 2);
            
	    ltype = Vect_read_line(&In, LPoints, LCats, line);
	    if (!(ltype & type))
		continue;
            if (!Vect_cat_get(LCats, field, &cat) && field != -1) {
                nskipped++;
		continue;
            }

            /* Assign CAT for layer 0 objects (i.e. boundaries) */
            if (field == -1)
                cat = -1;

	    if (LPoints->n_points <= 1) {
		write_point(&Out, LPoints->x[0], LPoints->y[0], LPoints->z[0],
			    cat, 0.0, driver, Fi);
	    }
	    else {		/* lines */
		write_line(&Out, LPoints, cat, vertex_type,
			   flag.inter->answer, dmax, driver, Fi);
	    }
	}

        if (nskipped > 0)
            G_warning(_("%d features without category in layer <%d> skipped. "
                        "Note that features without category (usually boundaries) are not "
                        "skipped when '%s=-1' is given."),
                      nskipped, field, opt.lfield->key);
    }

    if (type == GV_AREA) {
	int area, nareas, centroid, cat;

	nareas = Vect_get_num_areas(&In);
	for (area = 1; area <= nareas; area++) {
	    int i, isle, nisles;

	    G_percent(area, nareas, 2);
            
	    centroid = Vect_get_area_centroid(&In, area);
	    cat = -1;
	    if (centroid > 0) {
		Vect_read_line(&In, NULL, LCats, centroid);
		if (!Vect_cat_get(LCats, field, &cat))
		  continue;
	    }

	    Vect_get_area_points(&In, area, LPoints);

	    write_line(&Out, LPoints, cat, vertex_type, flag.inter->answer,
		       dmax, driver, Fi);

	    nisles = Vect_get_area_num_isles(&In, area);

	    for (i = 0; i < nisles; i++) {
		isle = Vect_get_area_isle(&In, area, i);
		Vect_get_isle_points(&In, isle, LPoints);

		write_line(&Out, LPoints, cat, vertex_type,
			   flag.inter->answer, dmax, driver, Fi);
	    }
	}
    }

    if (!flag.table->answer) {
	db_commit_transaction(driver);
	db_close_database_shutdown_driver(driver);
    }

    Vect_build(&Out);

    /* Free, close ... */
    Vect_close(&In);

    G_done_msg(_("%d points written to output vector map."),
               Vect_get_num_primitives(&Out, GV_POINT));

    Vect_close(&Out);
    
    exit(EXIT_SUCCESS);
}
Beispiel #14
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);
}
Beispiel #15
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;
}
Beispiel #16
0
int main(int argc, char **argv)
{
    int i, nsites, warn_once = 0;
    int all;
    long x, y;
    struct Cell_head window;
    struct GModule *module;
    struct
    {
	struct Option *input, *tests, *dfield, *layer;
    } parm;
    struct
    {
	struct Flag *q, *l, *region;
    } flag;
    double *w, *z;

    struct Map_info Map;
    int line, nlines, npoints;
    int field;
    struct line_pnts *Points;
    struct line_cats *Cats;
    struct bound_box box;

    /* Attributes */
    int nrecords;
    int ctype;
    struct field_info *Fi;
    dbDriver *Driver;
    dbCatValArray cvarr;

    G_gisinit(argv[0]);

    module = G_define_module();
    G_add_keyword(_("vector"));
    G_add_keyword(_("statistics"));
    G_add_keyword(_("points"));
    G_add_keyword(_("point pattern"));
    module->description = _("Tests for normality for vector points.");

    parm.input = G_define_standard_option(G_OPT_V_MAP);

    parm.layer = G_define_standard_option(G_OPT_V_FIELD);
    
    parm.tests = G_define_option();
    parm.tests->key = "tests";
    parm.tests->key_desc = "range";
    parm.tests->type = TYPE_STRING;
    parm.tests->multiple = YES;
    parm.tests->required = YES;
    parm.tests->label = _("Lists of tests (1-15)");
    parm.tests->description = _("E.g. 1,3-8,13");

    parm.dfield = G_define_standard_option(G_OPT_DB_COLUMN);
    parm.dfield->required = YES;

    flag.region = G_define_flag();
    flag.region->key = 'r';
    flag.region->description = _("Use only points in current region");

    flag.l = G_define_flag();
    flag.l->key = 'l';
    flag.l->description = _("Lognormality instead of normality");
    
    if (G_parser(argc, argv))
	exit(EXIT_FAILURE);
    
    all = flag.region->answer ? 0 : 1;

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

    field = Vect_get_field_number(&Map, parm.layer->answer);
    
    /* Read attributes */
    Fi = Vect_get_field(&Map, field);
    if (Fi == NULL) {
	G_fatal_error("Database connection not defined for layer %d", 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);

    nrecords = db_select_CatValArray(Driver, Fi->table, Fi->key, parm.dfield->answer,
				     NULL, &cvarr);
    G_debug(1, "nrecords = %d", nrecords);

    ctype = cvarr.ctype;
    if (ctype != DB_C_TYPE_INT && ctype != DB_C_TYPE_DOUBLE)
	G_fatal_error(_("Only numeric column type supported"));

    if (nrecords < 0)
	G_fatal_error(_("Unable to select data from table"));
    G_verbose_message(_("%d records selected from table"), nrecords);

    db_close_database_shutdown_driver(Driver);

    /* Read points */
    npoints = Vect_get_num_primitives(&Map, GV_POINT);
    z = (double *)G_malloc(npoints * sizeof(double));

    G_get_window(&window);
    Vect_region_box(&window, &box);

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

    nlines = Vect_get_num_lines(&Map);
    nsites = 0;
    for (line = 1; line <= nlines; line++) {
	int type, cat, ret, cval;
	double dval;

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

	type = Vect_read_line(&Map, Points, Cats, line);
	if (!(type & GV_POINT))
	    continue;

	if (!all) {
	    if (!Vect_point_in_box(Points->x[0], Points->y[0], 0.0, &box))
		continue;
	}

	Vect_cat_get(Cats, 1, &cat);

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

	/* find actual value */
	if (ctype == DB_C_TYPE_INT) {
	    ret = db_CatValArray_get_value_int(&cvarr, cat, &cval);
	    if (ret != DB_OK) {
		G_warning(_("No record for cat %d"), cat);
		continue;
	    }
	    dval = cval;
	}
	else if (ctype == DB_C_TYPE_DOUBLE) {
	    ret = db_CatValArray_get_value_double(&cvarr, cat, &dval);
	    if (ret != DB_OK) {
		G_warning(_("No record for cat %d"), cat);
		continue;
	    }
	}

	G_debug(3, "dval = %e", dval);
	z[nsites] = dval;
	nsites++;
    }

    G_verbose_message(_("Number of points: %d"), nsites);
    
    if (nsites <= 0)
	G_fatal_error(_("No points found"));

    if (nsites < 4)
	G_warning(_("Too small sample"));
    
    if (flag.l->answer) {
	warn_once = 0;
	for (i = 0; i < nsites; ++i) {
	    if (z[i] > 1.0e-10)
		z[i] = log10(z[i]);
	    else if (!warn_once) {
		G_warning(_("Negative or very small point values set to -10.0"));
		z[i] = -10.0;
		warn_once = 1;
	    }
	}
    }

    for (i = 0; parm.tests->answers[i]; i++)
	if (!scan_cats(parm.tests->answers[i], &x, &y)) {
	    G_usage();
	    exit(EXIT_FAILURE);
	}
    for (i = 0; parm.tests->answers[i]; i++) {
	scan_cats(parm.tests->answers[i], &x, &y);
	while (x <= y)
	    switch (x++) {
	    case 1:		/* moments */
		fprintf(stdout, _("Moments \\sqrt{b_1} and b_2: "));
		w = Cdhc_omnibus_moments(z, nsites);
		fprintf(stdout, "%g %g\n", w[0], w[1]);
		break;
	    case 2:		/* geary */
		fprintf(stdout, _("Geary's a-statistic & an approx. normal: "));
		w = Cdhc_geary_test(z, nsites);
		fprintf(stdout, "%g %g\n", w[0], w[1]);
		break;
	    case 3:		/* extreme deviates */
		fprintf(stdout, _("Extreme normal deviates: "));
		w = Cdhc_extreme(z, nsites);
		fprintf(stdout, "%g %g\n", w[0], w[1]);
		break;
	    case 4:		/* D'Agostino */
		fprintf(stdout, _("D'Agostino's D & an approx. normal: "));
		w = Cdhc_dagostino_d(z, nsites);
		fprintf(stdout, "%g %g\n", w[0], w[1]);
		break;
	    case 5:		/* Kuiper */
		fprintf(stdout,
			_("Kuiper's V (regular & modified for normality): "));
		w = Cdhc_kuipers_v(z, nsites);
		fprintf(stdout, "%g %g\n", w[1], w[0]);
		break;
	    case 6:		/* Watson */
		fprintf(stdout,
			_("Watson's U^2 (regular & modified for normality): "));
		w = Cdhc_watson_u2(z, nsites);
		fprintf(stdout, "%g %g\n", w[1], w[0]);
		break;
	    case 7:		/* Durbin */
		fprintf(stdout,
			_("Durbin's Exact Test (modified Kolmogorov): "));
		w = Cdhc_durbins_exact(z, nsites);
		fprintf(stdout, "%g\n", w[0]);
		break;
	    case 8:		/* Anderson-Darling */
		fprintf(stdout,
			_("Anderson-Darling's A^2 (regular & modified for normality): "));
		w = Cdhc_anderson_darling(z, nsites);
		fprintf(stdout, "%g %g\n", w[1], w[0]);
		break;
	    case 9:		/* Cramer-Von Mises */
		fprintf(stdout,
			_("Cramer-Von Mises W^2(regular & modified for normality): "));
		w = Cdhc_cramer_von_mises(z, nsites);
		fprintf(stdout, "%g %g\n", w[1], w[0]);
		break;
	    case 10:		/* Kolmogorov-Smirnov */
		fprintf(stdout,
			_("Kolmogorov-Smirnov's D (regular & modified for normality): "));
		w = Cdhc_kolmogorov_smirnov(z, nsites);
		fprintf(stdout, "%g %g\n", w[1], w[0]);
		break;
	    case 11:		/* chi-square */
		fprintf(stdout,
			_("Chi-Square stat (equal probability classes) and d.f.: "));
		w = Cdhc_chi_square(z, nsites);
		fprintf(stdout, "%g %d\n", w[0], (int)w[1]);
		break;
	    case 12:		/* Shapiro-Wilk */
		if (nsites > 50) {
		    G_warning(_("Shapiro-Wilk's W cannot be used for n > 50"));
		    if (nsites < 99)
			G_message(_("Use Weisberg-Binghams's W''"));
		}
		else {
		    fprintf(stdout, _("Shapiro-Wilk W: "));
		    w = Cdhc_shapiro_wilk(z, nsites);
		    fprintf(stdout, "%g\n", w[0]);
		}
		break;
	    case 13:		/* Weisberg-Bingham */
		if (nsites > 99 || nsites < 50)
		    G_warning(_("Weisberg-Bingham's W'' cannot be used for n < 50 or n > 99"));
		else {
		    fprintf(stdout, _("Weisberg-Bingham's W'': "));
		    w = Cdhc_weisberg_bingham(z, nsites);
		    fprintf(stdout, "%g\n", w[0]);
		}
		break;
	    case 14:		/* Royston */
		if (nsites > 2000)
		    G_warning(_("Royston only extended Shapiro-Wilk's W up to n = 2000"));
		else {
		    fprintf(stdout, _("Shapiro-Wilk W'': "));
		    w = Cdhc_royston(z, nsites);
		    fprintf(stdout, "%g\n", w[0]);
		}
		break;
	    case 15:		/* Kotz */
		fprintf(stdout, _("Kotz' T'_f (Lognormality vs. Normality): "));
		w = Cdhc_kotz_families(z, nsites);
		fprintf(stdout, "%g\n", w[0]);
		break;
	    default:
		break;
	    }
    }
    exit(EXIT_SUCCESS);
}