Example #1
0
/*!
   \brief Set values in 'varray' to 'value' from category string.

   If category of object of given type is in <em>cstring</em> (string
   representing category list like: '1,3,5-7'). <em>type</em> may be
   either: GV_AREA or: GV_POINT | GV_LINE | GV_BOUNDARY | GV_CENTROID

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

   \param Map vector map
   \param field layer number
   \param cstring pointer to string with categories
   \param type feature type
   \param value value to set up
   \param[out] varray varray structure to modify

   \return number of items set
   \return -1 on error
 */
int
Vect_set_varray_from_cat_string(const struct Map_info *Map, int field,
				const char *cstring, int type, int value,
				struct varray * varray)
{
    int ret;
    struct cat_list *Clist;

    G_debug(4, "Vect_set_varray_from_cat_string(): cstring = '%s'", cstring);

    Clist = Vect_new_cat_list();

    ret = Vect_str_to_cat_list(cstring, Clist);

    if (ret > 0)
	G_warning(_("%d errors in category string"), ret);

    G_debug(4, "  %d ranges in clist", Clist->n_ranges);

    ret =
	Vect_set_varray_from_cat_list(Map, field, Clist, type, value, varray);

    Vect_destroy_cat_list(Clist);

    return ret;
}
Example #2
0
/**
   \brief Select features by category
 
   \param[in] Map vector map
   \param[in] cl_orig original list of categories (previously selected)
   \param[in] layer layer number
   \param[in] type feature type
   \param[in] cat category string
   \param[in,out] List list of selected features

   \return number of selected lines
*/
int sel_by_cat(struct Map_info *Map, struct cat_list *cl_orig,
	       int layer, int type, char *cats, struct ilist *List)
{
    struct ilist *List_tmp, *List_tmp1;
    struct cat_list *cl;

    int i, cat;

    if (first_selection || cl_orig) {
	List_tmp = List;
	first_selection = 0;
    }
    else {
	List_tmp = Vect_new_list();
    }

    List_tmp1 = Vect_new_list();

    if (cl_orig == NULL) {
	cl = Vect_new_cat_list();

	Vect_str_to_cat_list(cats, cl);
    }
    else {
	cl = cl_orig;
    }

    for (i = 0; i < cl->n_ranges; i++) {
	for (cat = cl->min[i]; cat <= cl->max[i]; cat++) {
	    Vect_cidx_find_all(Map, layer, type, cat, List_tmp1);
	    Vect_list_append_list(List_tmp, List_tmp1);
	}
    }

    G_debug(1, "  %d lines selected (by category)", List_tmp->n_values);

    /* merge lists (only duplicate items) */
    if (List_tmp != List) {
	merge_lists(List, List_tmp);
	Vect_destroy_list(List_tmp);
    }

    Vect_destroy_list(List_tmp1);

    return List->n_values;
}
Example #3
0
/**
   \brief Select features by id

   \param[in] Map vector map
   \param[in] type feature type
   \param[in] ids ids list
   \param[in,out] List list of selected features
 
   \return number of selected lines
*/
int sel_by_id(struct Map_info *Map, int type, char *ids, struct ilist *List)
{
    int i;
    int num, id;
    struct cat_list *il;	/* NOTE: this is not cat list, but list of id's */
    struct ilist *List_tmp;

    if (first_selection) {
	List_tmp = List;
	first_selection = 0;
    }
    else {
	List_tmp = Vect_new_list();
    }

    il = Vect_new_cat_list();
    Vect_str_to_cat_list(ids, il);

    num = Vect_get_num_lines(Map);

    for (i = 0; i < il->n_ranges; i++) {
	for (id = 1; id <= num; id++) {
	    if (!(Vect_read_line(Map, NULL, NULL, id) & type)) {
		continue;
	    }
	    if (id >= il->min[i] && id <= il->max[i]) {
		Vect_list_append(List_tmp, id);
	    }
	}
    }

    G_debug(1, "  %d lines selected (by id)", List_tmp->n_values);

    /* merge lists (only duplicate items) */
    if (List_tmp != List) {
	merge_lists(List, List_tmp);
	Vect_destroy_list(List_tmp);
    }

    Vect_destroy_cat_list(il);

    return List->n_values;
}
Example #4
0
int main(int argc, char **argv)
{
    int ret, level;
    int stat, type, display;
    int chcat;
    int has_color, has_fcolor;
    struct color_rgb color, fcolor;
    double size;
    int default_width;
    double width_scale;
    double minreg, maxreg, reg;
    char map_name[GNAME_MAX];
    
    struct GModule *module;
    struct Option *map_opt;
    struct Option *color_opt, *fcolor_opt, *rgbcol_opt, *zcol_opt;
    struct Option *type_opt, *display_opt;
    struct Option *icon_opt, *size_opt, *sizecolumn_opt, *rotcolumn_opt;
    struct Option *where_opt;
    struct Option *field_opt, *cat_opt, *lfield_opt;
    struct Option *lcolor_opt, *bgcolor_opt, *bcolor_opt;
    struct Option *lsize_opt, *font_opt, *enc_opt, *xref_opt, *yref_opt;
    struct Option *attrcol_opt, *maxreg_opt, *minreg_opt;
    struct Option *width_opt, *wcolumn_opt, *wscale_opt;
    struct Option *leglab_opt;
    struct Option *icon_line_opt, *icon_area_opt;
    struct Flag *id_flag, *cats_acolors_flag, *sqrt_flag, *legend_flag;
    char *desc;
    
    struct cat_list *Clist;
    LATTR lattr;
    struct Map_info Map;
    struct Cell_head window;
    struct bound_box box;
    double overlap;

    stat = 0;
    /* Initialize the GIS calls */
    G_gisinit(argv[0]);

    module = G_define_module();
    G_add_keyword(_("display"));
    G_add_keyword(_("graphics"));
    G_add_keyword(_("vector"));
    module->description = _("Displays user-specified vector map "
			    "in the active graphics frame.");
    
    map_opt = G_define_standard_option(G_OPT_V_MAP);

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

    display_opt = G_define_option();
    display_opt->key = "display";
    display_opt->type = TYPE_STRING;
    display_opt->required = YES;
    display_opt->multiple = YES;
    display_opt->answer = "shape";
    display_opt->options = "shape,cat,topo,vert,dir,zcoor";
    display_opt->description = _("Display");
    desc = NULL;
    G_asprintf(&desc,
	       "shape;%s;cat;%s;topo;%s;vert;%s;dir;%s;zcoor;%s",
	       _("Display geometry of features"),
	       _("Display category numbers of features"),
	       _("Display topology information (nodes, edges)"),
               _("Display vertices of features"),
	       _("Display direction of linear features"),
	       _("Display z-coordinate of features (only for 3D vector maps)"));
    display_opt->descriptions = desc;
    
    /* Query */
    type_opt = G_define_standard_option(G_OPT_V_TYPE);
    type_opt->answer = "point,line,area,face";
    type_opt->options = "point,line,boundary,centroid,area,face";
    type_opt->guisection = _("Selection");
    
    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");


    /* Colors */
    color_opt = G_define_standard_option(G_OPT_CN);
    color_opt->label = _("Feature color");
    color_opt->guisection = _("Colors");
    
    fcolor_opt = G_define_standard_option(G_OPT_CN);
    fcolor_opt->key = "fill_color";
    fcolor_opt->answer = "200:200:200";
    fcolor_opt->label = _("Area fill color");
    fcolor_opt->guisection = _("Colors");

    rgbcol_opt = G_define_standard_option(G_OPT_DB_COLUMN);
    rgbcol_opt->key = "rgb_column";
    rgbcol_opt->guisection = _("Colors");
    rgbcol_opt->label = _("Colorize features according color definition column");
    rgbcol_opt->description = _("Color definition in R:G:B form");
    
    zcol_opt = G_define_standard_option(G_OPT_M_COLR);
    zcol_opt->key = "zcolor";
    zcol_opt->description = _("Colorize point or area features according to z-coordinate");
    zcol_opt->guisection = _("Colors");

    /* Lines */
    width_opt = G_define_option();
    width_opt->key = "width";
    width_opt->type = TYPE_INTEGER;
    width_opt->answer = "0";
    width_opt->guisection = _("Lines");
    width_opt->description = _("Line width");

    wcolumn_opt = G_define_standard_option(G_OPT_DB_COLUMN);
    wcolumn_opt->key = "width_column";
    wcolumn_opt->guisection = _("Lines");
    wcolumn_opt->label = _("Name of numeric column containing line width");
    wcolumn_opt->description = _("These values will be scaled by width_scale");

    wscale_opt = G_define_option();
    wscale_opt->key = "width_scale";
    wscale_opt->type = TYPE_DOUBLE;
    wscale_opt->answer = "1";
    wscale_opt->guisection = _("Lines");
    wscale_opt->description = _("Scale factor for width_column");

    /* Symbols */
    icon_opt = G_define_option();
    icon_opt->key = "icon";
    icon_opt->type = TYPE_STRING;
    icon_opt->required = NO;
    icon_opt->multiple = NO;
    icon_opt->guisection = _("Symbols");
    icon_opt->answer = "basic/x";
    /* This could also use ->gisprompt = "old,symbol,symbol" instead of ->options */
    icon_opt->options = icon_files();
    icon_opt->description = _("Point and centroid symbol");

    size_opt = G_define_option();
    size_opt->key = "size";
    size_opt->type = TYPE_DOUBLE;
    size_opt->answer = "5";
    size_opt->guisection = _("Symbols");
    size_opt->label = _("Symbol size");
    size_opt->description =
	_("When used with the size_column option this becomes the scale factor");

    sizecolumn_opt = G_define_standard_option(G_OPT_DB_COLUMN);
    sizecolumn_opt->key = "size_column";
    sizecolumn_opt->guisection = _("Symbols");
    sizecolumn_opt->description =
	_("Name of numeric column containing symbol size");

    rotcolumn_opt = G_define_standard_option(G_OPT_DB_COLUMN);
    rotcolumn_opt->key = "rotation_column";
    rotcolumn_opt->guisection = _("Symbols");
    rotcolumn_opt->label =
	_("Name of numeric column containing symbol rotation angle");
    rotcolumn_opt->description =
	_("Measured in degrees CCW from east");

    icon_area_opt = G_define_option();
    icon_area_opt->key = "icon_area";
    icon_area_opt->type = TYPE_STRING;
    icon_area_opt->required = NO;
    icon_area_opt->multiple = NO;
    icon_area_opt->guisection = _("Legend");
    icon_area_opt->answer = "legend/area";
    icon_area_opt->options = icon_files();
    icon_area_opt->description = _("Area/boundary symbol for legend");

    icon_line_opt = G_define_option();
    icon_line_opt->key = "icon_line";
    icon_line_opt->type = TYPE_STRING;
    icon_line_opt->required = NO;
    icon_line_opt->multiple = NO;
    icon_line_opt->guisection = _("Legend");
    icon_line_opt->answer = "legend/line";
    icon_line_opt->options = icon_files();
    icon_line_opt->description = _("Line symbol for legend");

    leglab_opt = G_define_option();
    leglab_opt->key = "legend_label";
    leglab_opt->type = TYPE_STRING;
    leglab_opt->guisection = _("Legend");
    leglab_opt->description = _("Label to display after symbol in vector legend");

    /* Labels */
    lfield_opt = G_define_standard_option(G_OPT_V_FIELD);
    lfield_opt->key = "label_layer";
    lfield_opt->required = NO;
    lfield_opt->guisection = _("Labels");
    lfield_opt->label =
	_("Layer number for labels (default: the given layer number)");
    
    attrcol_opt = G_define_standard_option(G_OPT_DB_COLUMN);
    attrcol_opt->key = "attribute_column";
    attrcol_opt->multiple = NO;	/* or fix attr.c, around line 102 */
    attrcol_opt->guisection = _("Labels");
    attrcol_opt->description = _("Name of column to be displayed as a label");

    lcolor_opt = G_define_standard_option(G_OPT_C);
    lcolor_opt->key = "label_color";
    lcolor_opt->answer = "red";
    lcolor_opt->label = _("Label color");
    lcolor_opt->guisection = _("Labels");

    bgcolor_opt = G_define_standard_option(G_OPT_CN);
    bgcolor_opt->key = "label_bgcolor";
    bgcolor_opt->answer = "none";
    bgcolor_opt->guisection = _("Labels");
    bgcolor_opt->label = _("Label background color");

    bcolor_opt = G_define_standard_option(G_OPT_CN);
    bcolor_opt->key = "label_bcolor";
    bcolor_opt->type = TYPE_STRING;
    bcolor_opt->answer = "none";
    bcolor_opt->guisection = _("Labels");
    bcolor_opt->label = _("Label border color");

    lsize_opt = G_define_option();
    lsize_opt->key = "label_size";
    lsize_opt->type = TYPE_INTEGER;
    lsize_opt->answer = "8";
    lsize_opt->guisection = _("Labels");
    lsize_opt->description = _("Label size (pixels)");

    font_opt = G_define_option();
    font_opt->key = "font";
    font_opt->type = TYPE_STRING;
    font_opt->guisection = _("Labels");
    font_opt->description = _("Font name");

    enc_opt = G_define_option();
    enc_opt->key = "encoding";
    enc_opt->type = TYPE_STRING;
    enc_opt->guisection = _("Labels");
    enc_opt->description = _("Text encoding");

    xref_opt = G_define_option();
    xref_opt->key = "xref";
    xref_opt->type = TYPE_STRING;
    xref_opt->guisection = _("Labels");
    xref_opt->answer = "left";
    xref_opt->options = "left,center,right";
    xref_opt->description = _("Label horizontal justification");

    yref_opt = G_define_option();
    yref_opt->key = "yref";
    yref_opt->type = TYPE_STRING;
    yref_opt->guisection = _("Labels");
    yref_opt->answer = "center";
    yref_opt->options = "top,center,bottom";
    yref_opt->description = _("Label vertical justification");

    minreg_opt = G_define_option();
    minreg_opt->key = "minreg";
    minreg_opt->type = TYPE_DOUBLE;
    minreg_opt->required = NO;
    minreg_opt->description =
	_("Minimum region size (average from height and width) "
	  "when map is displayed");

    maxreg_opt = G_define_option();
    maxreg_opt->key = "maxreg";
    maxreg_opt->type = TYPE_DOUBLE;
    maxreg_opt->required = NO;
    maxreg_opt->description =
	_("Maximum region size (average from height and width) "
	  "when map is displayed");

    /* Colors */
    cats_acolors_flag = G_define_flag();
    cats_acolors_flag->key = 'c';
    cats_acolors_flag->guisection = _("Colors");
    cats_acolors_flag->description =
	_("Random colors according to category number "
	  "(or layer number if 'layer=-1' is given)");

    /* Query */
    id_flag = G_define_flag();
    id_flag->key = 'i';
    id_flag->guisection = _("Selection");
    id_flag->description = _("Use values from 'cats' option as feature id");

    sqrt_flag = G_define_flag();
    sqrt_flag->key = 'r';
    sqrt_flag->label = _("Use square root of the value of size_column");
    sqrt_flag->description =
	_("This makes circle areas proportionate to the size_column values "
	  "instead of circle radius");
    sqrt_flag->guisection = _("Symbols");

    legend_flag = G_define_flag();
    legend_flag->key = 's';
    legend_flag->label = _("Do not show this layer in vector legend");
    legend_flag->guisection = _("Legend");

    /* Check command line */
    if (G_parser(argc, argv))
	exit(EXIT_FAILURE);

    D_open_driver();
    
    G_get_set_window(&window);
    
    /* Check min/max region */
    reg = ((window.east - window.west) + (window.north - window.south)) / 2;
    if (minreg_opt->answer) {
	minreg = atof(minreg_opt->answer);

	if (reg < minreg) {
	    G_important_message(_("Region size is lower than minreg, nothing displayed"));
	    exit(EXIT_SUCCESS);
	}
    }
    if (maxreg_opt->answer) {
	maxreg = atof(maxreg_opt->answer);

	if (reg > maxreg) {
	    G_important_message(_("Region size is greater than maxreg, nothing displayed"));
	    exit(EXIT_SUCCESS);
	}
    }

    strcpy(map_name, map_opt->answer);

    default_width = atoi(width_opt->answer);
    if (default_width < 0)
	default_width = 0;
    width_scale = atof(wscale_opt->answer);

    if (cats_acolors_flag->answer && rgbcol_opt->answer) {
	G_warning(_("The -%c flag and <%s> option cannot be used together, "
		    "the -%c flag will be ignored!"), 
                  cats_acolors_flag->key, rgbcol_opt->key, cats_acolors_flag->key);
        cats_acolors_flag->answer = FALSE;
    }

    color = G_standard_color_rgb(WHITE);
    has_color = option_to_color(&color, color_opt->answer);
    fcolor = G_standard_color_rgb(WHITE);
    has_fcolor = option_to_color(&fcolor, fcolor_opt->answer);
    
    size = atof(size_opt->answer);

    /* if where_opt was specified select categories from db 
     * otherwise parse cat_opt */
    Clist = Vect_new_cat_list();
    Clist->field = atoi(field_opt->answer);

    /* open vector */
    level = Vect_open_old2(&Map, map_name, "", field_opt->answer);

    chcat = 0;
    if (where_opt->answer) {
	if (Clist->field < 1)
	    G_fatal_error(_("Option <%s> must be > 0"), field_opt->key);
	chcat = 1;
	option_to_where(&Map, Clist, where_opt->answer);
    }
    else if (cat_opt->answer) {
	if (Clist->field < 1 && !id_flag->answer)
	    G_fatal_error(_("Option <%s> must be > 0"), field_opt->key);
	chcat = 1;
	ret = Vect_str_to_cat_list(cat_opt->answer, Clist);
	if (ret > 0)
	    G_warning(n_("%d error in cat option", "%d errors in cat option", ret), ret);
    }
    
    type = Vect_option_to_types(type_opt);
    
    display = option_to_display(display_opt);

    /* labels */
    options_to_lattr(&lattr, lfield_opt->answer,
		     lcolor_opt->answer, bgcolor_opt->answer, bcolor_opt->answer,
		     atoi(lsize_opt->answer), font_opt->answer, enc_opt->answer,
		     xref_opt->answer, yref_opt->answer);

    D_setup(0);
    D_set_reduction(1.0);

    G_verbose_message(_("Plotting..."));

    if (level >= 2)
	Vect_get_map_box(&Map, &box);

    if (level >= 2 && (window.north < box.S || window.south > box.N ||
		       window.east < box.W ||
		       window.west > G_adjust_easting(box.E, &window))) {
	G_warning(_("The bounding box of the map is outside the current region, "
		    "nothing drawn"));
    }
    else {
	overlap = G_window_percentage_overlap(&window, box.N, box.S,
					      box.E, box.W);
	G_debug(1, "overlap = %f \n", overlap);
	if (overlap < 1)
	    Vect_set_constraint_region(&Map, window.north, window.south,
				       window.east, window.west,
				       PORT_DOUBLE_MAX, -PORT_DOUBLE_MAX);

	/* default line width */
	if (!wcolumn_opt->answer)
	    D_line_width(default_width);

	if (display & DISP_SHAPE) {
	    stat += display_shape(&Map, type, Clist, &window,
				  has_color ? &color : NULL, has_fcolor ? &fcolor : NULL, chcat,
				  icon_opt->answer, size, sizecolumn_opt->answer,
				  sqrt_flag->answer ? TRUE : FALSE, rotcolumn_opt->answer,
				  id_flag->answer ? TRUE : FALSE, 
				  cats_acolors_flag->answer ? TRUE : FALSE, rgbcol_opt->answer,
				  default_width,  wcolumn_opt->answer, width_scale,
				  zcol_opt->answer);
	    
	    if (wcolumn_opt->answer)
		D_line_width(default_width);
	}

	if (has_color) {
	    D_RGB_color(color.r, color.g, color.b);
	    if (display & DISP_DIR)
		stat += display_dir(&Map, type, Clist, chcat, size);
	}

	if (!legend_flag->answer) {
		write_into_legfile(&Map, type, leglab_opt->answer, map_name,
			   icon_opt->answer, size_opt->answer, 
			   color_opt->answer, fcolor_opt->answer, 
			   width_opt->answer, icon_area_opt->answer,
			   icon_line_opt->answer, sizecolumn_opt->answer);
	}

	/* reset line width: Do we need to get line width from display
	 * driver (not implemented)?  It will help restore previous line
	 * width (not just 0) determined by another module (e.g.,
	 * d.linewidth). */
	if (!wcolumn_opt->answer)
	    D_line_width(0);
	
	if (display & DISP_CAT)
	    stat += display_label(&Map, type, Clist, &lattr, chcat);

	if (attrcol_opt->answer)
	    stat += display_attr(&Map, type, attrcol_opt->answer, Clist, &lattr, chcat);

	if (display & DISP_ZCOOR)
	    stat += display_zcoor(&Map, type, &lattr);

	if (display & DISP_VERT)
            stat += display_vert(&Map, type, &lattr, size);

	if (display & DISP_TOPO)
            stat += display_topo(&Map, type, &lattr, size);
    }

    D_save_command(G_recreate_command());
    D_close_driver();

    Vect_close(&Map);
    Vect_destroy_cat_list(Clist);

    if (stat != 0) {
	G_fatal_error(_("Rendering failed"));
    }
    
    G_done_msg(" ");
    exit(EXIT_SUCCESS);
}
Example #5
0
File: main.c Project: caomw/grass
int main(int argc, char **argv)
{
    int i, j, ret, centre, line, centre1, centre2, tfield, tucfield;
    int nlines, nnodes, type, ltype, afield, nfield, geo, cat;
    int node, node1, node2;
    double cost, e1cost, e2cost, n1cost, n2cost, s1cost, s2cost, l, l1;
    struct Option *map, *output;
    struct Option *afield_opt, *nfield_opt, *afcol, *abcol, *ncol, *type_opt,
	*term_opt, *cost_opt, *tfield_opt, *tucfield_opt;
    struct Flag *geo_f, *turntable_f;
    struct GModule *module;
    struct Map_info Map, Out;
    struct cat_list *catlist;
    CENTER *Centers = NULL;
    int acentres = 0, ncentres = 0;
    NODE *Nodes;
    struct line_cats *Cats;
    struct line_pnts *Points, *SPoints;
    int niso, aiso;
    double *iso;
    int npnts1, apnts1 = 0, npnts2, apnts2 = 0;
    ISOPOINT *pnts1 = NULL, *pnts2 = NULL;
    int next_iso;

    G_gisinit(argv[0]);

    module = G_define_module();
    G_add_keyword(_("vector"));
    G_add_keyword(_("network"));
    G_add_keyword(_("isolines"));
    module->label = _("Splits net by cost isolines.");
    module->description =
	_
	("Splits net to bands between cost isolines (direction from center). "
	 "Center node must be opened (costs >= 0). "
	 "Costs of center node are used in calculation.");

    map = G_define_standard_option(G_OPT_V_INPUT);
    output = G_define_standard_option(G_OPT_V_OUTPUT);

    term_opt = G_define_standard_option(G_OPT_V_CATS);
    term_opt->key = "ccats";
    term_opt->required = YES;
    term_opt->description =
	_("Categories of centers (points on nodes) to which net "
	  "will be allocated, "
	  "layer for this categories is given by nlayer option");

    cost_opt = G_define_option();
    cost_opt->key = "costs";
    cost_opt->type = TYPE_INTEGER;
    cost_opt->multiple = YES;
    cost_opt->required = YES;
    cost_opt->description = _("Costs for isolines");

    afield_opt = G_define_standard_option(G_OPT_V_FIELD);
    afield_opt->key = "alayer";
    afield_opt->answer = "1";
    afield_opt->required = YES;
    afield_opt->label = _("Arc layer");

    type_opt = G_define_standard_option(G_OPT_V_TYPE);
    type_opt->options = "line,boundary";
    type_opt->answer = "line,boundary";
    type_opt->required = YES;
    type_opt->label = _("Arc type");

    nfield_opt = G_define_standard_option(G_OPT_V_FIELD);
    nfield_opt->key = "nlayer";
    nfield_opt->answer = "2";
    nfield_opt->required = YES;
    nfield_opt->label = _("Node layer");

    afcol = G_define_standard_option(G_OPT_DB_COLUMN);
    afcol->key = "afcolumn";
    afcol->description =
	_("Arc forward/both direction(s) cost column (number)");
    afcol->guisection = _("Cost");

    abcol = G_define_standard_option(G_OPT_DB_COLUMN);
    abcol->key = "abcolumn";
    abcol->description = _("Arc backward direction cost column (number)");
    abcol->guisection = _("Cost");

    ncol = G_define_standard_option(G_OPT_DB_COLUMN);
    ncol->key = "ncolumn";
    ncol->description = _("Node cost column (number)");
    ncol->guisection = _("Cost");

    turntable_f = G_define_flag();
    turntable_f->key = 't';
    turntable_f->description = _("Use turntable");
    turntable_f->guisection = _("Turntable");

    tfield_opt = G_define_standard_option(G_OPT_V_FIELD);
    tfield_opt->key = "tlayer";
    tfield_opt->answer = "3";
    tfield_opt->label = _("Layer with turntable");
    tfield_opt->description =
	_("Relevant only with -t flag");
    tfield_opt->guisection = _("Turntable");

    tucfield_opt = G_define_standard_option(G_OPT_V_FIELD);
    tucfield_opt->key = "tuclayer";
    tucfield_opt->answer = "4";
    tucfield_opt->label = _("Layer with unique categories used in turntable");
    tucfield_opt->description =
	_("Relevant only with -t flag");
    tucfield_opt->guisection = _("Turntable");

    geo_f = G_define_flag();
    geo_f->key = 'g';
    geo_f->description =
	_("Use geodesic calculation for longitude-latitude locations");

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

    Vect_check_input_output_name(map->answer, output->answer, G_FATAL_EXIT);

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

    type = Vect_option_to_types(type_opt);

    catlist = Vect_new_cat_list();
    Vect_str_to_cat_list(term_opt->answer, catlist);

    /* Iso costs */
    aiso = 1;
    iso = (double *)G_malloc(aiso * sizeof(double));
    /* Set first iso to 0 */
    iso[0] = 0;
    niso = 1;
    i = 0;
    while (cost_opt->answers[i]) {
	if (niso == aiso) {
	    aiso += 1;
	    iso = (double *)G_realloc(iso, aiso * sizeof(double));
	}
	iso[niso] = atof(cost_opt->answers[i]);
	if (iso[niso] <= 0)
	    G_fatal_error(_("Wrong iso cost: %f"), iso[niso]);

	if (iso[niso] <= iso[niso - 1])
	    G_fatal_error(_("Iso cost: %f less than previous"), iso[niso]);

	G_verbose_message(_("Iso cost %d: %f"), niso, iso[niso]);
	niso++;
	i++;
    }

    /* Should not happen: */
    if (niso < 2)
	G_warning(_
		  ("Not enough costs, everything reachable falls to first band"));

    if (geo_f->answer)
	geo = 1;
    else
	geo = 0;

    Vect_set_open_level(2);
    if (Vect_open_old(&Map, map->answer, "") < 0)
	G_fatal_error(_("Unable to open vector map <%s>"), map->answer);

    afield = Vect_get_field_number(&Map, afield_opt->answer);
    nfield = Vect_get_field_number(&Map, nfield_opt->answer);
    tfield = Vect_get_field_number(&Map, tfield_opt->answer);
    tucfield = Vect_get_field_number(&Map, tucfield_opt->answer);

    /* Build graph */
    if (turntable_f->answer)
	Vect_net_ttb_build_graph(&Map, type, afield, nfield, tfield, tucfield,
				 afcol->answer, abcol->answer, ncol->answer,
				 geo, 0);
    else
	Vect_net_build_graph(&Map, type, afield, nfield, afcol->answer,
			     abcol->answer, ncol->answer, geo, 0);

    nnodes = Vect_get_num_nodes(&Map);
    nlines = Vect_get_num_lines(&Map);

    /* Create list of centres based on list of categories */
    for (i = 1; i <= nlines; i++) {
	ltype = Vect_get_line_type(&Map, i);
	if (!(ltype & GV_POINT))
	    continue;

	Vect_read_line(&Map, Points, Cats, i);
	node =
	    Vect_find_node(&Map, Points->x[0], Points->y[0], Points->z[0], 0,
			   0);
	if (!node) {
	    G_warning(_("Point is not connected to the network"));
	    continue;
	}
	if (!(Vect_cat_get(Cats, nfield, &cat)))
	    continue;
	if (Vect_cat_in_cat_list(cat, catlist)) {
	    Vect_net_get_node_cost(&Map, node, &n1cost);
	    if (n1cost == -1) {	/* closed */
		G_warning(_("Centre at closed node (costs = -1) ignored"));
	    }
	    else {
		if (acentres == ncentres) {
		    acentres += 1;
		    Centers =
			(CENTER *) G_realloc(Centers,
					     acentres * sizeof(CENTER));
		}
		Centers[ncentres].cat = cat;
		Centers[ncentres].node = node;
		G_debug(2, "centre = %d node = %d cat = %d", ncentres,
			node, cat);
		ncentres++;
	    }
	}
    }

    G_message(_("Number of centres: %d (nlayer %d)"), ncentres, nfield);

    if (ncentres == 0)
	G_warning(_
		  ("Not enough centres for selected nlayer. Nothing will be allocated."));

    /* alloc and reset space for all nodes */
    if (turntable_f->answer) {
	/* if turntable is used we are looking for lines as destinations, instead of the intersections (nodes) */
	Nodes = (NODE *) G_calloc((nlines * 2 + 2), sizeof(NODE));
	for (i = 2; i <= (nlines * 2 + 2); i++) {
	    Nodes[i].centre = -1;/* NOTE: first two items of Nodes are not used */
	}

    }
    else {
	Nodes = (NODE *) G_calloc((nnodes + 1), sizeof(NODE));
	for (i = 1; i <= nnodes; i++) {
	    Nodes[i].centre = -1;
	}
    }

    apnts1 = 1;
    pnts1 = (ISOPOINT *) G_malloc(apnts1 * sizeof(ISOPOINT));

    apnts2 = 1;
    pnts2 = (ISOPOINT *) G_malloc(apnts2 * sizeof(ISOPOINT));

    /* Fill Nodes by neares centre and costs from that centre */
    for (centre = 0; centre < ncentres; centre++) {
	node1 = Centers[centre].node;
	Vect_net_get_node_cost(&Map, node1, &n1cost);
	G_debug(2, "centre = %d node = %d cat = %d", centre, node1,
		Centers[centre].cat);
	G_message(_("Calculating costs from centre %d..."), centre + 1);
	if (turntable_f->answer)
	    for (line = 1; line <= nlines; line++) {
		G_debug(5, "  node1 = %d line = %d", node1, line);
		Vect_net_get_node_cost(&Map, line, &n2cost);
		/* closed, left it as not attached */

		if (Vect_read_line(&Map, Points, Cats, line) < 0)
		    continue;
		if (Vect_get_line_type(&Map, line) != GV_LINE)
		    continue;
		if (!Vect_cat_get(Cats, tucfield, &cat))
		    continue;

		for (j = 0; j < 2; j++) {
		    if (j == 1)
			cat *= -1;

		    ret =
			Vect_net_ttb_shortest_path(&Map, node1, 0, cat, 1,
						   tucfield, NULL,
						   &cost);
		    if (ret == -1) {
			continue;
		    }		/* node unreachable */

		    /* We must add centre node costs (not calculated by Vect_net_shortest_path() ), but
	             *  only if centre and node are not identical, because at the end node cost is add later */
		    if (ret != 1)
			cost += n1cost;

		    G_debug(5,
			    "Arc nodes: %d %d cost: %f (x old cent: %d old cost %f",
			    node1, line, cost, Nodes[line * 2 + j].centre,
			    Nodes[line * 2 + j].cost);
		    if (Nodes[line * 2 + j].centre == -1 ||
			cost < Nodes[line * 2 + j].cost) {
			Nodes[line * 2 + j].cost = cost;
			Nodes[line * 2 + j].centre = centre;
		    }
		}
	    }
	else
	    for (node2 = 1; node2 <= nnodes; node2++) {
		G_percent(node2, nnodes, 1);
		G_debug(5, "  node1 = %d node2 = %d", node1, node2);
		Vect_net_get_node_cost(&Map, node2, &n2cost);
		if (n2cost == -1) {
		    continue;
		}		/* closed, left it as not attached */

		ret = Vect_net_shortest_path(&Map, node1, node2, NULL, &cost);
		if (ret == -1) {
		    continue;
		}		/* node unreachable */

		/* We must add centre node costs (not calculated by Vect_net_shortest_path() ), but
		 *  only if centre and node are not identical, because at the end node cost is add later */
		if (node1 != node2)
		    cost += n1cost;
		G_debug(5,
			"Arc nodes: %d %d cost: %f (x old cent: %d old cost %f",
			node1, node2, cost, Nodes[node2].centre,
			Nodes[node2].cost);
		if (Nodes[node2].centre == -1 || cost < Nodes[node2].cost) {
		    Nodes[node2].cost = cost;
		    Nodes[node2].centre = centre;
		}
	    }
    }

    /* Write arcs to new map */
    if (Vect_open_new(&Out, output->answer, Vect_is_3d(&Map)) < 0)
	G_fatal_error(_("Unable to create vector map <%s>"), output->answer);

    Vect_hist_command(&Out);

    G_message("Generating isolines...");
    nlines = Vect_get_num_lines(&Map);
    for (line = 1; line <= nlines; line++) {
	G_percent(line, nlines, 2);

	ltype = Vect_read_line(&Map, Points, NULL, line);
	if (!(ltype & type)) {
	    continue;
	}

	l = Vect_line_length(Points);
	if (l == 0)
	    continue;

	if (turntable_f->answer) {
	    centre1 = Nodes[line * 2].centre;
	    centre2 = Nodes[line * 2 + 1].centre;
	    s1cost = Nodes[line * 2].cost;
	    s2cost = Nodes[line * 2 + 1].cost;
	    n1cost = n2cost = 0;
	}
	else {
	    Vect_get_line_nodes(&Map, line, &node1, &node2);
	    centre1 = Nodes[node1].centre;
	    centre2 = Nodes[node2].centre;
	    s1cost = Nodes[node1].cost;
	    s2cost = Nodes[node2].cost;

	    Vect_net_get_node_cost(&Map, node1, &n1cost);
	    Vect_net_get_node_cost(&Map, node2, &n2cost);

	}

	Vect_net_get_line_cost(&Map, line, GV_FORWARD, &e1cost);
	Vect_net_get_line_cost(&Map, line, GV_BACKWARD, &e2cost);

	G_debug(3, "Line %d : length = %f", line, l);
	G_debug(3, "Arc centres: %d %d (nodes: %d %d)", centre1, centre2,
		node1, node2);

	G_debug(3, "  s1cost = %f n1cost = %f e1cost = %f", s1cost, n1cost,
		e1cost);
	G_debug(3, "  s2cost = %f n2cost = %f e2cost = %f", s2cost, n2cost,
		e2cost);


	/* First check if arc is reachable from at least one side */
	if ((centre1 != -1 && n1cost != -1 && e1cost != -1) ||
	    (centre2 != -1 && n2cost != -1 && e2cost != -1)) {
	    /* Line is reachable at least from one side */
	    G_debug(3, "  -> arc is reachable");

	    /* Add costs of node to starting costs */
	    s1cost += n1cost;
	    s2cost += n2cost;

	    e1cost /= l;
	    e2cost /= l;

	    /* Find points on isolines along the line in both directions, add them to array,
	     *  first point is placed at the beginning/end of line */
	    /* Forward */
	    npnts1 = 0;		/* in case this direction is closed */
	    if (centre1 != -1 && n1cost != -1 && e1cost != -1) {
		/* Find iso for beginning of the line */
		next_iso = 0;
		for (i = niso - 1; i >= 0; i--) {
		    if (iso[i] <= s1cost) {
			next_iso = i;
			break;
		    }
		}
		/* Add first */
		pnts1[0].iso = next_iso;
		pnts1[0].distance = 0;
		npnts1++;
		next_iso++;

		/* Calculate distances for points along line */
		while (next_iso < niso) {
		    if (e1cost == 0)
			break;	/* Outside line */
		    l1 = (iso[next_iso] - s1cost) / e1cost;
		    if (l1 >= l)
			break;	/* Outside line */

		    if (npnts1 == apnts1) {
			apnts1 += 1;
			pnts1 =
			    (ISOPOINT *) G_realloc(pnts1,
						   apnts1 * sizeof(ISOPOINT));
		    }
		    pnts1[npnts1].iso = next_iso;
		    pnts1[npnts1].distance = l1;
		    G_debug(3,
			    "  forward %d : iso %d : distance %f : cost %f",
			    npnts1, next_iso, l1, iso[next_iso]);
		    npnts1++;
		    next_iso++;
		}
	    }
	    G_debug(3, "  npnts1 = %d", npnts1);

	    /* Backward */
	    npnts2 = 0;
	    if (centre2 != -1 && n2cost != -1 && e2cost != -1) {
		/* Find iso for beginning of the line */
		next_iso = 0;
		for (i = niso - 1; i >= 0; i--) {
		    if (iso[i] <= s2cost) {
			next_iso = i;
			break;
		    }
		}
		/* Add first */
		pnts2[0].iso = next_iso;
		pnts2[0].distance = l;
		npnts2++;
		next_iso++;

		/* Calculate distances for points along line */
		while (next_iso < niso) {
		    if (e2cost == 0)
			break;	/* Outside line */
		    l1 = (iso[next_iso] - s2cost) / e2cost;
		    if (l1 >= l)
			break;	/* Outside line */

		    if (npnts2 == apnts2) {
			apnts2 += 1;
			pnts2 =
			    (ISOPOINT *) G_realloc(pnts2,
						   apnts2 * sizeof(ISOPOINT));
		    }
		    pnts2[npnts2].iso = next_iso;
		    pnts2[npnts2].distance = l - l1;
		    G_debug(3,
			    "  backward %d : iso %d : distance %f : cost %f",
			    npnts2, next_iso, l - l1, iso[next_iso]);
		    npnts2++;
		    next_iso++;
		}
	    }
	    G_debug(3, "  npnts2 = %d", npnts2);

	    /* Limit number of points by maximum costs in reverse direction, this may remove
	     *  also the first point in one direction, but not in both */
	    /* Forward */
	    if (npnts2 > 0) {
		for (i = 0; i < npnts1; i++) {
		    G_debug(3,
			    "  pnt1 = %d dist1 = %f iso1 = %d max iso2 = %d",
			    i, pnts1[i].distance, pnts1[i].iso,
			    pnts2[npnts2 - 1].iso);
		    if (pnts2[npnts2 - 1].iso < pnts1[i].iso) {
			G_debug(3, "    -> cut here");
			npnts1 = i;
			break;
		    }
		}
	    }
	    G_debug(3, "  npnts1 cut = %d", npnts1);

	    /* Backward */
	    if (npnts1 > 0) {
		for (i = 0; i < npnts2; i++) {
		    G_debug(3,
			    "  pnt2 = %d dist2 = %f iso2 = %d max iso1 = %d",
			    i, pnts2[i].distance, pnts2[i].iso,
			    pnts1[npnts1 - 1].iso);
		    if (pnts1[npnts1 - 1].iso < pnts2[i].iso) {
			G_debug(3, "    -> cut here");
			npnts2 = i;
			break;
		    }
		}
	    }
	    G_debug(3, "  npnts2 cut = %d", npnts2);

	    /* Biggest cost shoud be equal if exist (npnts > 0). Cut out overlapping segments,
	     *  this can cut only points on line but not first points */
	    if (npnts1 > 1 && npnts2 > 1) {
		while (npnts1 > 1 && npnts2 > 1) {
		    if (pnts1[npnts1 - 1].distance >= pnts2[npnts2 - 1].distance) {	/* overlap */
			npnts1--;
			npnts2--;
		    }
		    else {
			break;
		    }
		}
	    }
	    G_debug(3, "  npnts1 2. cut = %d", npnts1);
	    G_debug(3, "  npnts2 2. cut = %d", npnts2);

	    /* Now we have points in both directions which may not overlap, npoints in one
	     *  direction may be 0 but not both */

	    /* Join both arrays, iso of point is for next segment (point is at the beginning) */
	    /* In case npnts1 == 0 add point at distance 0 */
	    if (npnts1 == 0) {
		G_debug(3,
			"  npnts1 = 0 -> add first at distance 0, cat = %d",
			pnts2[npnts2 - 1].iso);
		pnts1[0].iso = pnts2[npnts2 - 1].iso;	/* use last point iso in reverse direction */
		pnts1[0].distance = 0;
		npnts1++;
	    }
	    for (i = npnts2 - 1; i >= 0; i--) {
		/* Check if identical */
		if (pnts1[npnts1 - 1].distance == pnts2[i].distance)
		    continue;

		if (npnts1 == apnts1) {
		    apnts1 += 1;
		    pnts1 =
			(ISOPOINT *) G_realloc(pnts1,
					       apnts1 * sizeof(ISOPOINT));
		}
		pnts1[npnts1].iso = pnts2[i].iso - 1;	/* last may be -1, but it is not used */
		pnts1[npnts1].distance = pnts2[i].distance;
		npnts1++;
	    }
	    /* In case npnts2 == 0 add point at the end */
	    if (npnts2 == 0) {
		pnts1[npnts1].iso = 0;	/* not used */
		pnts1[npnts1].distance = l;
		npnts1++;
	    }

	    /* Create line segments. */
	    for (i = 1; i < npnts1; i++) {
		cat = pnts1[i - 1].iso + 1;
		G_debug(3, "  segment %f - %f cat %d", pnts1[i - 1].distance,
			pnts1[i].distance, cat);
		ret =
		    Vect_line_segment(Points, pnts1[i - 1].distance,
				      pnts1[i].distance, SPoints);
		if (ret == 0) {
		    G_warning(_
			      ("Cannot get line segment, segment out of line"));
		}
		else {
		    Vect_reset_cats(Cats);
		    Vect_cat_set(Cats, 1, cat);
		    Vect_write_line(&Out, ltype, SPoints, Cats);
		}
	    }
	}
	else {
	    /* arc is not reachable */
	    G_debug(3, "  -> arc is not reachable");
	    Vect_reset_cats(Cats);
	    Vect_write_line(&Out, ltype, Points, Cats);
	}
    }

    Vect_build(&Out);

    /* Free, ... */
    G_free(Nodes);
    G_free(Centers);
    Vect_close(&Map);
    Vect_close(&Out);

    exit(EXIT_SUCCESS);
}
Example #6
0
int main(int argc, char *argv[])
{
    struct GModule *module;
    struct GParams params;
    struct Map_info Map;
    struct Map_info **BgMap;	/* backgroud vector maps */
    int nbgmaps;		/* number of registrated background maps */
    enum mode action_mode;
    FILE *ascii;

    int i;
    int move_first, snap;
    int ret, layer;
    double move_x, move_y, move_z, thresh[3];

    struct line_pnts *coord;

    struct ilist *List;

    struct cat_list *Clist;

    ascii = NULL;
    List = NULL;
    BgMap = NULL;
    nbgmaps = 0;
    coord = NULL;
    Clist = NULL;

    G_gisinit(argv[0]);

    module = G_define_module();
    module->overwrite = TRUE;
    G_add_keyword(_("vector"));
    G_add_keyword(_("editing"));
    G_add_keyword(_("geometry"));
    module->description = _("Edits a vector map, allows adding, deleting "
			    "and modifying selected vector features.");

    if (!parser(argc, argv, &params, &action_mode))
	exit(EXIT_FAILURE);

    /* get list of categories */
    Clist = Vect_new_cat_list();
    if (params.cat->answer && Vect_str_to_cat_list(params.cat->answer, Clist)) {
	G_fatal_error(_("Unable to get category list <%s>"),
		      params.cat->answer);
    }

    /* open input file */
    if (params.in->answer) {
	if (strcmp(params.in->answer, "-") != 0) {
	    ascii = fopen(params.in->answer, "r");
	    if (ascii == NULL)
		G_fatal_error(_("Unable to open file <%s>"),
			      params.in->answer);
	}
	else {
	    ascii = stdin;
	}
    }
    if (!ascii && action_mode == MODE_ADD)
	G_fatal_error(_("Required parameter <%s> not set"), params.in->key);
    
    if (action_mode == MODE_CREATE) {
	int overwrite;

	overwrite = G_check_overwrite(argc, argv);
	if (G_find_vector2(params.map->answer, G_mapset())) {
	    if (!overwrite)
		G_fatal_error(_("Vector map <%s> already exists"),
			      params.map->answer);
	}

	/* 3D vector maps? */
	ret = Vect_open_new(&Map, params.map->answer, WITHOUT_Z);
	if (Vect_maptype(&Map) == GV_FORMAT_OGR_DIRECT) {
	    int type;
	    type = Vect_option_to_types(params.type);
	    if (type != GV_POINT && type != GV_LINE &&
		type != GV_BOUNDARY)
		G_fatal_error(_("Supported feature type for OGR layer: "
				"%s, %s or %s"), "point", "line", "boundary");
	    V2_open_new_ogr(&Map, type);
	}
	if (ret == -1) {
	    G_fatal_error(_("Unable to create vector map <%s>"),
			  params.map->answer);
	}

	G_debug(1, "Map created");

	if (ascii) {
	    /* also add new vector features */
	    action_mode = MODE_ADD;
	}
    }
    else {			/* open selected vector file */
	if (action_mode == MODE_ADD)	/* write */
	    ret = Vect_open_update2(&Map, params.map->answer, G_mapset(), params.fld->answer);
	else			/* read-only -- select features */
	    ret = Vect_open_old2(&Map, params.map->answer, G_mapset(), params.fld->answer);

	if (ret < 2)
	    G_fatal_error(_("Unable to open vector map <%s> at topological level %d"),
			  params.map->answer, 2);
    }

    G_debug(1, "Map opened");

    /* open backgroud maps */
    if (params.bmaps->answer) {
	i = 0;

	while (params.bmaps->answers[i]) {
	    const char *bmap = params.bmaps->answers[i];
	    const char *mapset = G_find_vector2(bmap, "");
	    if (!mapset)
		G_fatal_error(_("Vector map <%s> not found"), bmap);

	    if (strcmp(
		    G_fully_qualified_name(params.map->answer, G_mapset()),
		    G_fully_qualified_name(bmap, mapset)) == 0) {
		G_fatal_error(_("Unable to open vector map <%s> as the background map. "
			       "It is given as vector map to be edited."),
			      bmap);
	    }
	    nbgmaps++;
	    BgMap = (struct Map_info **)G_realloc(
		BgMap, nbgmaps * sizeof(struct Map_info *));
	    BgMap[nbgmaps - 1] =
		(struct Map_info *)G_malloc(sizeof(struct Map_info));
	    if (Vect_open_old(BgMap[nbgmaps - 1], bmap, "") == -1)
		G_fatal_error(_("Unable to open vector map <%s>"), bmap);
	    G_verbose_message(_("Background vector map <%s> registered"), bmap);
	    i++;
	}
    }

    layer = Vect_get_field_number(&Map, params.fld->answer);
    i = 0;
    while (params.maxdist->answers[i]) {
	switch (i) {
	case THRESH_COORDS:
	    thresh[THRESH_COORDS] =
		max_distance(atof(params.maxdist->answers[THRESH_COORDS]));
	    thresh[THRESH_SNAP] = thresh[THRESH_QUERY] =
		thresh[THRESH_COORDS];
	    break;
	case THRESH_SNAP:
	    thresh[THRESH_SNAP] =
		max_distance(atof(params.maxdist->answers[THRESH_SNAP]));
	    break;
	case THRESH_QUERY:
	    thresh[THRESH_QUERY] =
		atof(params.maxdist->answers[THRESH_QUERY]);
	    break;
	default:
	    break;
	}
	i++;
    }

    move_first = params.move_first->answer ? 1 : 0;
    snap = NO_SNAP;
    if (strcmp(params.snap->answer, "node") == 0)
	snap = SNAP;
    else if (strcmp(params.snap->answer, "vertex") == 0)
	snap = SNAPVERTEX;
    if (snap != NO_SNAP && thresh[THRESH_SNAP] <= 0) {
	G_warning(_("Threshold for snapping must be > 0. No snapping applied."));
	snap = NO_SNAP;
    }
    
    if (action_mode != MODE_CREATE && action_mode != MODE_ADD) {
	/* select lines */
	List = Vect_new_list();
	G_message(_("Selecting features..."));
	if (action_mode == MODE_COPY && BgMap && BgMap[0]) {
	    List = select_lines(BgMap[0], action_mode, &params, thresh, List);
	}
	else {
	    List = select_lines(&Map, action_mode, &params, thresh, List);
	}
    }

    if ((action_mode != MODE_CREATE && action_mode != MODE_ADD &&
	 action_mode != MODE_SELECT)) {
	if (List->n_values < 1) {
	    G_warning(_("No features selected, nothing to edit"));
	    action_mode = MODE_NONE;
	    ret = 0;
	}
	else {
	    /* reopen the map for updating */
	    if (action_mode == MODE_ZBULK && !Vect_is_3d(&Map)) {
		Vect_close(&Map);
		G_fatal_error(_("Vector map <%s> is not 3D. Tool '%s' requires 3D vector map. "
			       "Please convert the vector map "
			       "to 3D using e.g. %s."), params.map->answer,
			      params.tool->answer, "v.extrude");
	    }
	    Vect_close(&Map);

	    Vect_open_update2(&Map, params.map->answer, G_mapset(), params.fld->answer);
	}
    }

    /* coords option -> array */
    if (params.coord->answers) {
	coord = Vect_new_line_struct();
	int i = 0;
	double east, north;

	while (params.coord->answers[i]) {
	    east = atof(params.coord->answers[i]);
	    north = atof(params.coord->answers[i + 1]);
	    Vect_append_point(coord, east, north, 0.0);
	    i += 2;
	}
    }

    /* perform requested editation */
    switch (action_mode) {
    case MODE_CREATE:
	break;
    case MODE_ADD:
	if (!params.header->answer)
	    Vect_read_ascii_head(ascii, &Map);
	int num_lines;
	num_lines = Vect_get_num_lines(&Map);
	
	ret = Vect_read_ascii(ascii, &Map);
	G_message(_("%d features added"), ret);
	if (ret > 0) {
	    int iline;
	    struct ilist *List_added;
	    
	    List_added = Vect_new_list();
	    for (iline = num_lines + 1; iline <= Vect_get_num_lines(&Map); iline++)
		Vect_list_append(List_added, iline);
	    
	    G_verbose_message(_("Threshold value for snapping is %.2f"),
			      thresh[THRESH_SNAP]);
	    if (snap != NO_SNAP) { /* apply snapping */
		/* snap to vertex ? */
		Vedit_snap_lines(&Map, BgMap, nbgmaps, List_added,
				 thresh[THRESH_SNAP],
				 snap == SNAP ? FALSE : TRUE); 
	    }
	    if (params.close->answer) {	/* close boundaries */
		int nclosed;

		nclosed = close_lines(&Map, GV_BOUNDARY, thresh[THRESH_SNAP]);
		G_message(_("%d boundaries closed"), nclosed);
	    }
	    Vect_destroy_list(List_added);
	}
	break;
    case MODE_DEL:
	ret = Vedit_delete_lines(&Map, List);
	G_message(_("%d features deleted"), ret);
	break;
    case MODE_MOVE:
	move_x = atof(params.move->answers[0]);
	move_y = atof(params.move->answers[1]);
	move_z = atof(params.move->answers[2]);
	G_verbose_message(_("Threshold value for snapping is %.2f"),
			  thresh[THRESH_SNAP]);
	ret = Vedit_move_lines(&Map, BgMap, nbgmaps, List, move_x, move_y, move_z, snap, thresh[THRESH_SNAP]);
	G_message(_("%d features moved"), ret);
	break;
    case MODE_VERTEX_MOVE:
	move_x = atof(params.move->answers[0]);
	move_y = atof(params.move->answers[1]);
	move_z = atof(params.move->answers[2]);
	G_verbose_message(_("Threshold value for snapping is %.2f"),
			  thresh[THRESH_SNAP]);
	ret = Vedit_move_vertex(&Map, BgMap, nbgmaps, List, coord, thresh[THRESH_COORDS], thresh[THRESH_SNAP], move_x, move_y, move_z, move_first, snap);
	G_message(_("%d vertices moved"), ret);
	break;
    case MODE_VERTEX_ADD:
	ret = Vedit_add_vertex(&Map, List, coord, thresh[THRESH_COORDS]);
	G_message(_("%d vertices added"), ret);
	break;
    case MODE_VERTEX_DELETE:
	ret = Vedit_remove_vertex(&Map, List, coord, thresh[THRESH_COORDS]);
	G_message(_("%d vertices removed"), ret);
	break;
    case MODE_BREAK:
	if (params.coord->answer) {
	    ret = Vedit_split_lines(&Map, List,
				    coord, thresh[THRESH_COORDS], NULL);
	}
	else {
	    ret = Vect_break_lines_list(&Map, List, NULL, GV_LINES, NULL);
	}
	G_message(_("%d lines broken"), ret);
	break;
    case MODE_CONNECT:
	G_verbose_message(_("Threshold value for snapping is %.2f"),
			  thresh[THRESH_SNAP]);
	ret = Vedit_connect_lines(&Map, List, thresh[THRESH_SNAP]);
	G_message(_("%d lines connected"), ret);
	break;
    case MODE_MERGE:
	ret = Vedit_merge_lines(&Map, List);
	G_message(_("%d lines merged"), ret);
	break;
    case MODE_SELECT:
	ret = print_selected(List);
	break;
    case MODE_CATADD:
	ret = Vedit_modify_cats(&Map, List, layer, 0, Clist);
	G_message(_("%d features modified"), ret);
	break;
    case MODE_CATDEL:
	ret = Vedit_modify_cats(&Map, List, layer, 1, Clist);
	G_message(_("%d features modified"), ret);
	break;
    case MODE_COPY:
	if (BgMap && BgMap[0]) {
	    if (nbgmaps > 1)
		G_warning(_("Multiple background maps were given. "
			    "Selected features will be copied only from "
			    "vector map <%s>."),
			  Vect_get_full_name(BgMap[0]));

	    ret = Vedit_copy_lines(&Map, BgMap[0], List);
	}
	else {
	    ret = Vedit_copy_lines(&Map, NULL, List);
	}
	G_message(_("%d features copied"), ret);
	break;
    case MODE_SNAP:
	G_verbose_message(_("Threshold value for snapping is %.2f"),
			  thresh[THRESH_SNAP]);
	ret = snap_lines(&Map, List, thresh[THRESH_SNAP]);
	break;
    case MODE_FLIP:
	ret = Vedit_flip_lines(&Map, List);
	G_message(_("%d lines flipped"), ret);
	break;
    case MODE_NONE:
	break;
    case MODE_ZBULK:{
	    double start, step;
	    double x1, y1, x2, y2;

	    start = atof(params.zbulk->answers[0]);
	    step = atof(params.zbulk->answers[1]);

	    x1 = atof(params.bbox->answers[0]);
	    y1 = atof(params.bbox->answers[1]);
	    x2 = atof(params.bbox->answers[2]);
	    y2 = atof(params.bbox->answers[3]);

	    ret = Vedit_bulk_labeling(&Map, List,
				      x1, y1, x2, y2, start, step);

	    G_message(_("%d lines labeled"), ret);
	    break;
	}
    case MODE_CHTYPE:{
	    ret = Vedit_chtype_lines(&Map, List);

	    if (ret > 0) {
		G_message(_("%d features converted"), ret);
	    }
	    else {
		G_message(_("No feature modified"));
	    }
	    break;
	}
    default:
	G_warning(_("Operation not implemented"));
	ret = -1;
	break;
    }
    
    Vect_hist_command(&Map);

    /* build topology only if requested or if tool!=select */
    if (!(action_mode == MODE_SELECT || params.topo->answer == 1 ||
	 !MODE_NONE)) {
	Vect_build_partial(&Map, GV_BUILD_NONE);
	Vect_build(&Map);
    }

    if (List)
	Vect_destroy_list(List);

    Vect_close(&Map);

    G_debug(1, "Map closed");

    /* close background maps */
    for (i = 0; i < nbgmaps; i++) {
	Vect_close(BgMap[i]);
	G_free((void *)BgMap[i]);
    }
    G_free((void *)BgMap);

    if (coord)
	Vect_destroy_line_struct(coord);

    if (Clist)
	Vect_destroy_cat_list(Clist);

    G_done_msg(" ");

    if (ret > -1) {
	exit(EXIT_SUCCESS);
    }
    else {
	exit(EXIT_FAILURE);
    }
}
Example #7
0
/**
   \brief Select features according to SQL where statement

   \param[in] Map vector map
   \param[in] layer layer number
   \param[in] type feature type
   \param[in] where 'where' statement
   \param[in,out] List list of selected features
 
   \return number of selected lines
*/
int sel_by_where(struct Map_info *Map,
		 int layer, int type, char *where, struct ilist *List)
{
    struct cat_list *cat_list;
    struct ilist *List_tmp;
    struct field_info *Fi;
    dbDriver *driver;
    dbHandle handle;

    int *cats, ncats;

    if (first_selection) {
	List_tmp = List;
	first_selection = 0;
    }
    else {
	List_tmp = Vect_new_list();
    }

    cat_list = Vect_new_cat_list();

    if (layer < 1) {
	G_fatal_error(_("Layer must be > 0 for 'where'"));
    }

    Fi = Vect_get_field(Map, layer);

    if (!Fi) {
	G_fatal_error(_("Database connection not defined for layer %d"),
		      layer);
    }

    driver = db_start_driver(Fi->driver);

    if (!driver)
	G_fatal_error(_("Unable to start driver <%s>"), Fi->driver);

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

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

    db_close_database(driver);
    db_shutdown_driver(driver);

    Vect_array_to_cat_list(cats, ncats, cat_list);

    /* free array of cats */
    if (ncats >= 0)
	G_free(cats);

    sel_by_cat(Map, cat_list, layer, type, NULL, List_tmp);

    G_debug(1, "  %d lines selected (by where)", List_tmp->n_values);

    /* merge lists (only duplicate items) */
    if (List_tmp != List) {
	merge_lists(List, List_tmp);
	Vect_destroy_list(List_tmp);
    }

    Vect_destroy_cat_list(cat_list);

    return List->n_values;
}
Example #8
0
int main(int argc, char *argv[])
{
    struct Map_info In, Out;
    static struct line_pnts *Points;
    struct line_cats *Cats;
    struct field_info *Fi;
    struct cat_list *Clist;
    int i, j, ret, option, otype, type, with_z, step, id;
    int n_areas, centr, new_centr, nmodified;
    int open_level;
    double x, y;
    int cat, ocat, scat, *fields, nfields, field;
    struct GModule *module;
    struct Option *in_opt, *out_opt, *option_opt, *type_opt;
    struct Option *cat_opt, *field_opt, *step_opt, *id_opt;
    struct Flag *shell, *notab;
    FREPORT **freps;
    int nfreps, rtype, fld;
    char *desc;

    module = G_define_module();
    G_add_keyword(_("vector"));
    G_add_keyword(_("category"));
    G_add_keyword(_("layer"));
    module->description =
	_("Attaches, deletes or reports vector categories to map geometry.");

    in_opt = G_define_standard_option(G_OPT_V_INPUT);

    field_opt = G_define_standard_option(G_OPT_V_FIELD);
    field_opt->multiple = YES;
    field_opt->guisection = _("Selection");

    type_opt = G_define_standard_option(G_OPT_V3_TYPE);
    type_opt->answer = "point,line,centroid,face";
    type_opt->guisection = _("Selection");

    id_opt = G_define_standard_option(G_OPT_V_IDS);
    id_opt->label = _("Feature ids (by default all features are processed)");
    id_opt->guisection = _("Selection");

    out_opt = G_define_standard_option(G_OPT_V_OUTPUT);
    out_opt->required = NO;

    option_opt = G_define_option();
    option_opt->key = "option";
    option_opt->type = TYPE_STRING;
    option_opt->required = YES;
    option_opt->multiple = NO;
    option_opt->options = "add,del,chlayer,sum,report,print,layers,transfer";
    option_opt->description = _("Action to be done");
    desc = NULL;
    G_asprintf(&desc,
	       "add;%s;"
	       "del;%s;"
	       "chlayer;%s;"
	       "sum;%s;"
	       "transfer;%s;"
	       "report;%s;"
	       "print;%s;"
	       "layers;%s",
	       _("add a category to features without category in the given layer"),
	       _("delete category (cat=-1 to delete all categories of given layer)"),
	       _("change layer number (e.g. layer=3,1 changes layer 3 to layer 1)"),
	       _("add the value specified by cat option to the current category value"),
	       _("copy values from one layer to another (e.g. layer=1,2,3 copies values from layer 1 to layer 2 and 3)"),
	       _("print report (statistics), in shell style: layer type count min max"),
	       _("print category values, layers are separated by '|', more cats in the same layer are separated by '/'"),
	       _("print only layer numbers"));
    option_opt->descriptions = desc;
    
    cat_opt = G_define_standard_option(G_OPT_V_CAT);
    cat_opt->answer = "1";

    step_opt = G_define_option();
    step_opt->key = "step";
    step_opt->type = TYPE_INTEGER;
    step_opt->required = NO;
    step_opt->multiple = NO;
    step_opt->answer = "1";
    step_opt->description = _("Category increment");

    shell = G_define_flag();
    shell->key = 'g';
    shell->label = _("Shell script style, currently only for report");
    shell->description = _("Format: layer type count min max");
    
    notab = G_define_standard_flag(G_FLG_V_TABLE);
    notab->description = _("Do not copy attribute table(s)");

    G_gisinit(argv[0]);

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

    /* read options */
    option = 0;
    switch (option_opt->answer[0]) {
    case ('a'):
	option = O_ADD;
	break;
    case ('d'):
	option = O_DEL;
	break;
    case ('c'):
	option = O_CHFIELD;
	G_warning(_("Database connection and attribute tables for concerned layers are not changed"));
	break;
    case ('s'):
	option = O_SUM;
	break;
    case ('t'):
        option = O_TRANS;
        break;
    case ('r'):
	option = O_REP;
	break;
    case ('p'):
	option = O_PRN;
	break;
    case ('l'):
	option = O_LYR;
	break;
    }

    if (option == O_LYR) {
	/* print vector layer numbers */
	/* open vector on level 2 head only, this is why this option
	 * is processed here, all other options need (?) to fully open 
	 * the input vector */
	Vect_set_open_level(2);
	if (Vect_open_old_head2(&In, in_opt->answer, "", field_opt->answer) < 2) {
	    G_fatal_error(_("Unable to open vector map <%s> at topological level %d"),
			  Vect_get_full_name(&In), 2);
	}
	if (In.format == GV_FORMAT_NATIVE) {
	    nfields = Vect_cidx_get_num_fields(&In);
	    for (i = 0; i < nfields; i++) {
		if ((field = Vect_cidx_get_field_number(&In, i)) > 0)
		    fprintf(stdout, "%d\n", field);
	    }
	}
	else
	    fprintf(stdout, "%s\n", field_opt->answer);

	Vect_close(&In);
	exit(EXIT_SUCCESS);
    }

    cat = atoi(cat_opt->answer);
    step = atoi(step_opt->answer);
    otype = Vect_option_to_types(type_opt);

    if (cat < 0 && option == O_ADD)
	G_fatal_error(_("Invalid category number (must be equal to or greater than 0). "
			"Normally category number starts at 1."));

    /* collect ids */
    if (id_opt->answer) {
	Clist = Vect_new_cat_list();
	Clist->field = atoi(field_opt->answer);
	ret = Vect_str_to_cat_list(id_opt->answer, Clist);
	if (ret > 0) {
	    G_warning(n_("%d error in id option",
                         "%d errors in id option",
                         ret), ret);
	}
    }
    else {
	Clist = NULL;
    }

    if ((option != O_REP) && (option != O_PRN) && (option != O_LYR)) {
	if (out_opt->answer == NULL)
	    G_fatal_error(_("Output vector wasn't entered"));

	Vect_check_input_output_name(in_opt->answer, out_opt->answer,
				     G_FATAL_EXIT);
    }

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

    /* do we need topology ? */
    if ((option == O_ADD && (otype & GV_AREA)) ||
	(option == O_REP && (otype & GV_AREA)) ||
        (option == O_TRANS) || /* topo for cidx check */
        (option == O_LYR)) /* topo for cidx check */
	open_level = 2;
    else
	open_level = 1;

    /* open input vector */
    if (open_level > 1) {
	Vect_set_open_level(open_level);
	if (Vect_open_old2(&In, in_opt->answer, "", field_opt->answer) < open_level) {
	    G_warning(_("Unable to open vector map <%s> at topological level %d"),
			  Vect_get_full_name(&In), open_level);
	    open_level = 1;
	}
    }
    if (open_level == 1) {
	Vect_set_open_level(open_level);
	if (Vect_open_old2(&In, in_opt->answer, "", field_opt->answer) < open_level) {
	    G_fatal_error(_("Unable to open vector map <%s> at topological level %d"),
			  Vect_get_full_name(&In), open_level);
	}
    }

    /* read fields */
    i = nfields = 0;
    while (field_opt->answers[i++])
	nfields++;
    fields = (int *)G_malloc(nfields * sizeof(int));
    
    i = 0;
    while (field_opt->answers[i]) {
	fields[i] = Vect_get_field_number(&In, field_opt->answers[i]);
	i++;
    }
    if (nfields > 1 && option != O_PRN && option != O_CHFIELD && option != O_TRANS)
	G_fatal_error(_("Too many layers for this operation"));
    
    if (nfields != 2 && option == O_CHFIELD)
	G_fatal_error(_("2 layers must be specified"));

    if (option == O_TRANS && open_level == 1 && nfields < 2) {
	G_fatal_error(_("2 layers must be specified"));
    }

    if (option == O_TRANS && open_level > 1) {
	/* check if field[>0] already exists */
	if (nfields > 1) {
	    for(i = 1; i < nfields; i++) {
		if (Vect_cidx_get_field_index(&In, fields[i]) != -1)
		    G_warning(_("Categories already exist in layer %d"), fields[i]);
	    }
	}
	/* find next free layer number */
	else if (nfields == 1) {
	    int max = -1;
	    
	    for (i = 0; i < Vect_cidx_get_num_fields(&In); i++) {
		if (max < Vect_cidx_get_field_number(&In, i))
		    max = Vect_cidx_get_field_number(&In, i);
	    }
	    max++;

	    nfields++;
	    fields = (int *)G_realloc(fields, nfields * sizeof(int));
	    fields[nfields - 1] = max;
	}
    }

    if (otype & GV_AREA && option == O_TRANS && !(otype & GV_CENTROID))
	otype |= GV_CENTROID;

    /* open output vector if needed */
    if (option == O_ADD || option == O_DEL || option == O_CHFIELD ||
	option == O_SUM || option == O_TRANS) {
	with_z = Vect_is_3d(&In);

	if (0 > Vect_open_new(&Out, out_opt->answer, with_z)) {
	    Vect_close(&In);
	    exit(EXIT_FAILURE);
	}

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

    id = 0;

    nmodified = 0;

    if (option == O_ADD || option == O_DEL || option == O_CHFIELD ||
	option == O_SUM || option == O_TRANS) {
	G_message(_("Processing features..."));
    }

    switch (option) {
    case (O_ADD):
	/* Lines */
	while ((type = Vect_read_next_line(&In, Points, Cats)) > 0) {
	    id++;
	    if (type & otype && (!Clist ||
				 (Clist &&
				  Vect_cat_in_cat_list(id, Clist) == TRUE))) {
		if ((Vect_cat_get(Cats, fields[0], &ocat)) == 0) {
		    if (ocat < 0) {
			if (Vect_cat_set(Cats, fields[0], cat) > 0) {
			    nmodified++;
			}
			cat += step;
		    }
		}
	    }
	    Vect_write_line(&Out, type, Points, Cats);
	}
	/* Areas */
	if ((otype & GV_AREA) && open_level > 1) {
	    n_areas = Vect_get_num_areas(&In);
	    new_centr = 0;
	    for (i = 1; i <= n_areas; i++) {
		centr = Vect_get_area_centroid(&In, i);
		if (centr > 0)
		    continue;	/* Centroid exists and may be processed as line */
		ret = Vect_get_point_in_area(&In, i, &x, &y);
		if (ret < 0) {
		    G_warning(_("Unable to calculate area centroid"));
		    continue;
		}
		Vect_reset_line(Points);
		Vect_reset_cats(Cats);
		Vect_append_point(Points, x, y, 0.0);
		if (Vect_cat_set(Cats, fields[0], cat) > 0) {
		    nmodified++;
		}
		cat += step;
		Vect_write_line(&Out, GV_CENTROID, Points, Cats);
		new_centr++;
	    }
	    if (new_centr > 0) 
		G_message(n_("%d new centroid placed in output map",
                             "%d new centroids placed in output map",
                             new_centr), new_centr);
	}
	break;

    case (O_TRANS):
	/* Lines */
	while ((type = Vect_read_next_line(&In, Points, Cats)) > 0) {
	    id++;
	    if (type & otype && (!Clist ||
				 (Clist &&
				  Vect_cat_in_cat_list(id, Clist) == TRUE))) {
		int n = Cats->n_cats;

		scat = -1;
		for (i = 0; i < n; i++) {
		    if (Cats->field[i] == fields[0]) {
			scat = Cats->cat[i];
			for (j = 1; j < nfields; j++) {
			    if (Vect_cat_set(Cats, fields[j], scat) > 0) {
				G_debug(4, "Copy cat %i of field %i to field %i", scat, fields[0], fields[j]);
			    }
			}
		    }
		}
		if (scat != -1)
		    nmodified++;
	    }
	    Vect_write_line(&Out, type, Points, Cats);
	}
	break;

    case (O_DEL):
	while ((type = Vect_read_next_line(&In, Points, Cats)) > 0) {
	    id++;
	    if (type & otype && (!Clist ||
				 (Clist &&
				  Vect_cat_in_cat_list(id, Clist) == TRUE))) {
		ret = Vect_field_cat_del(Cats, fields[0], cat);
		if (ret > 0) {
		    nmodified++;
		}
	    }
	    Vect_write_line(&Out, type, Points, Cats);
	}
	break;

    case (O_CHFIELD):
	while ((type = Vect_read_next_line(&In, Points, Cats)) > 0) {
	    id++;
	    if (type & otype && (!Clist ||
				 (Clist &&
				  Vect_cat_in_cat_list(id, Clist) == TRUE))) {
		i = 0;
		while (i < Cats->n_cats) {
		    if (Cats->field[i] == fields[0]) {
			int found = -1;
			
			/* check if cat already exists in layer fields[1] */
			for (j = 0; j < Cats->n_cats; j++) {
			    if (Cats->field[j] == fields[1] &&
				Cats->cat[j] == Cats->cat[i]) {
				found = j;
				break;
			    }
			}
			/* does not exist, change layer */
			if (found < 0) {
			    Cats->field[i] = fields[1];
			    i++;
			}
			/* exists already in fields[1], delete from fields[0] */
			else
			    Vect_field_cat_del(Cats, fields[0], Cats->cat[found]);
			nmodified++;
		    }
		}
	    }
	    Vect_write_line(&Out, type, Points, Cats);
	}
	break;

    case (O_SUM):
	while ((type = Vect_read_next_line(&In, Points, Cats)) > 0) {
	    id++;
	    if (type & otype && (!Clist ||
				 (Clist &&
				  Vect_cat_in_cat_list(id, Clist) == TRUE))) {
		for (i = 0; i < Cats->n_cats; i++) {
		    if (Cats->field[i] == fields[0]) {
			Cats->cat[i] += cat;
		    }
		}
		nmodified++;
	    }
	    Vect_write_line(&Out, type, Points, Cats);
	}
	break;

    case (O_REP):
	nfreps = 0;
	freps = NULL;
	while ((type = Vect_read_next_line(&In, Points, Cats)) > 0) {
	    id++;
	    if (Clist && Vect_cat_in_cat_list(id, Clist) == FALSE)
		continue;

	    switch (type) {
	    case (GV_POINT):
		rtype = FR_POINT;
		break;
	    case (GV_LINE):
		rtype = FR_LINE;
		break;
	    case (GV_BOUNDARY):
		rtype = FR_BOUNDARY;
		break;
	    case (GV_CENTROID):
		rtype = FR_CENTROID;
		break;
	    case (GV_FACE):
		rtype = FR_FACE;
		break;
	    case (GV_KERNEL):
		rtype = FR_KERNEL;
		break;
	    default:
		rtype = FR_UNKNOWN;
	    }

	    for (i = 0; i < Cats->n_cats; i++) {
		field = Cats->field[i];
		cat = Cats->cat[i];


		ret = FALSE;
		for (j = 0; j < nfreps; j++) {
		    if (freps[j]->field == field) {
			fld = j;
			ret = TRUE;
			break;
		    }
		}
		if (!ret) {	/* field report doesn't exist */
		    nfreps++;
		    freps =
			(FREPORT **) G_realloc(freps,
					       nfreps * sizeof(FREPORT *));
		    fld = nfreps - 1;
		    freps[fld] = (FREPORT *) G_calloc(1, sizeof(FREPORT));
		    freps[fld]->field = field;
		    for (j = 0; j < FRTYPES; j++) {
			/* cat '0' is valid category number */
			freps[fld]->min[j] = -1;
		    }
		    if ((Fi = Vect_get_field(&In, field)) != NULL) {
			freps[fld]->table = G_store(Fi->table);
		    }
		    else {
			freps[fld]->table = '\0';
		    }
		}

		freps[fld]->count[rtype]++;
		freps[fld]->count[FR_ALL]++;

		if (freps[fld]->min[rtype] == -1 ||
		    freps[fld]->min[rtype] > cat)
		    freps[fld]->min[rtype] = cat;

		if ((freps[fld]->max[rtype] == 0) ||
		    freps[fld]->max[rtype] < cat)
		    freps[fld]->max[rtype] = cat;

		if (freps[fld]->min[FR_ALL] == -1 ||
		    freps[fld]->min[FR_ALL] > cat)
		    freps[fld]->min[FR_ALL] = cat;

		if ((freps[fld]->max[FR_ALL] == 0) ||
		    freps[fld]->max[FR_ALL] < cat)
		    freps[fld]->max[FR_ALL] = cat;
	    }
	}
	/* Areas */
	if ((otype & GV_AREA) && open_level > 1 && !Clist) {
	    n_areas = Vect_get_num_areas(&In);
	    for (i = 1; i <= n_areas; i++) {
		int k;

		centr = Vect_get_area_centroid(&In, i);
		if (centr <= 0)
		    continue;	/* Area without centroid */
		    
		Vect_read_line(&In, NULL, Cats, centr);
		for (j = 0; j < Cats->n_cats; j++) {
		    field = Cats->field[j];
		    cat = Cats->cat[j];


		    ret = FALSE;
		    for (k = 0; k < nfreps; k++) {
			if (freps[k]->field == field) {
			    fld = k;
			    ret = TRUE;
			    break;
			}
		    }
		    if (!ret) {	/* field report doesn't exist */
			nfreps++;
			freps =
			    (FREPORT **) G_realloc(freps,
						   nfreps * sizeof(FREPORT *));
			fld = nfreps - 1;
			freps[fld] = (FREPORT *) G_calloc(1, sizeof(FREPORT));
			freps[fld]->field = field;
			for (j = 0; j < FRTYPES; j++) {
			    /* cat '0' is valid category number */
			    freps[fld]->min[k] = -1;
			}
			if ((Fi = Vect_get_field(&In, field)) != NULL) {
			    freps[fld]->table = G_store(Fi->table);
			}
			else {
			    freps[fld]->table = '\0';
			}
		    }

		    freps[fld]->count[FR_AREA]++;

		    if (freps[fld]->min[FR_AREA] == -1 ||
			freps[fld]->min[FR_AREA] > cat)
			freps[fld]->min[FR_AREA] = cat;

		    if ((freps[fld]->max[FR_AREA] == 0) ||
			freps[fld]->max[FR_AREA] < cat)
			freps[fld]->max[FR_AREA] = cat;
		}
	    }
	}
	for (i = 0; i < nfreps; i++) {
	    if (shell->answer) {
		if (freps[i]->count[FR_POINT] > 0)
		    fprintf(stdout, "%d point %d %d %d\n", freps[i]->field,
			    freps[i]->count[FR_POINT],
			    (freps[i]->min[FR_POINT] < 0 ? 0 : freps[i]->min[FR_POINT]),
			    freps[i]->max[FR_POINT]);

		if (freps[i]->count[FR_LINE] > 0)
		    fprintf(stdout, "%d line %d %d %d\n", freps[i]->field,
			    freps[i]->count[FR_LINE],
			    (freps[i]->min[FR_LINE] < 0 ? 0 : freps[i]->min[FR_LINE]),
			    freps[i]->max[FR_LINE]);

		if (freps[i]->count[FR_BOUNDARY] > 0)
		    fprintf(stdout, "%d boundary %d %d %d\n", freps[i]->field,
			    freps[i]->count[FR_BOUNDARY],
			    (freps[i]->min[FR_BOUNDARY] < 0 ? 0 : freps[i]->min[FR_BOUNDARY]),
			    freps[i]->max[FR_BOUNDARY]);

		if (freps[i]->count[FR_CENTROID] > 0)
		    fprintf(stdout, "%d centroid %d %d %d\n", freps[i]->field,
			    freps[i]->count[FR_CENTROID],
			    (freps[i]->min[FR_BOUNDARY] < 0 ? 0 : freps[i]->min[FR_BOUNDARY]),
			    freps[i]->max[FR_CENTROID]);

		if (freps[i]->count[FR_AREA] > 0)
		    fprintf(stdout, "%d area %d %d %d\n", freps[i]->field,
			    freps[i]->count[FR_AREA],
			    (freps[i]->min[FR_AREA] < 0 ? 0 : freps[i]->min[FR_AREA]),
			    freps[i]->max[FR_AREA]);

		if (freps[i]->count[FR_FACE] > 0)
		    fprintf(stdout, "%d face %d %d %d\n", freps[i]->field,
			    freps[i]->count[FR_FACE],
			    (freps[i]->min[FR_FACE] < 0 ? 0 : freps[i]->min[FR_FACE]),
			    freps[i]->max[FR_FACE]);

		if (freps[i]->count[FR_KERNEL] > 0)
		    fprintf(stdout, "%d kernel %d %d %d\n", freps[i]->field,
			    freps[i]->count[FR_KERNEL],
			    (freps[i]->min[FR_KERNEL] < 0 ? 0 : freps[i]->min[FR_KERNEL]),
			    freps[i]->max[FR_KERNEL]);

		if (freps[i]->count[FR_ALL] > 0)
		    fprintf(stdout, "%d all %d %d %d\n", freps[i]->field,
			    freps[i]->count[FR_ALL],
			    (freps[i]->min[FR_ALL] < 0 ? 0 : freps[i]->min[FR_ALL]),
			    freps[i]->max[FR_ALL]);
	    }
	    else {
		if (freps[i]->table != '\0') {
		    fprintf(stdout, "%s: %d/%s\n", _("Layer/table"),
			    freps[i]->field, freps[i]->table);
		}
		else {
		    fprintf(stdout, "%s: %d\n", _("Layer"), freps[i]->field);
		}
		fprintf(stdout, _("type       count        min        max\n"));
		fprintf(stdout, "%s    %7d %10d %10d\n", _("point"),
			freps[i]->count[FR_POINT],
			(freps[i]->min[FR_POINT] < 0) ? 0 : freps[i]->min[FR_POINT],
			freps[i]->max[FR_POINT]);
		fprintf(stdout, "%s     %7d %10d %10d\n", _("line"),
			freps[i]->count[FR_LINE],
			(freps[i]->min[FR_LINE] < 0) ? 0 : freps[i]->min[FR_LINE],
			freps[i]->max[FR_LINE]);
		fprintf(stdout, "%s %7d %10d %10d\n", _("boundary"),
			freps[i]->count[FR_BOUNDARY],
			(freps[i]->min[FR_BOUNDARY] < 0) ? 0 : freps[i]->min[FR_BOUNDARY],
			freps[i]->max[FR_BOUNDARY]);
		fprintf(stdout, "%s %7d %10d %10d\n", _("centroid"),
			freps[i]->count[FR_CENTROID],
			(freps[i]->min[FR_CENTROID] < 0) ? 0 : freps[i]->min[FR_CENTROID],
			freps[i]->max[FR_CENTROID]);
		fprintf(stdout, "%s     %7d %10d %10d\n", _("area"),
			freps[i]->count[FR_AREA],
			(freps[i]->min[FR_AREA] < 0) ? 0 : freps[i]->min[FR_AREA],
			freps[i]->max[FR_AREA]);
		fprintf(stdout, "%s     %7d %10d %10d\n", _("face"),
			freps[i]->count[FR_FACE],
			(freps[i]->min[FR_FACE] < 0) ? 0 : freps[i]->min[FR_FACE],
			freps[i]->max[FR_FACE]);
		fprintf(stdout, "%s   %7d %10d %10d\n", _("kernel"),
			freps[i]->count[FR_KERNEL],
			(freps[i]->min[FR_KERNEL] < 0) ? 0 : freps[i]->min[FR_KERNEL],
			freps[i]->max[FR_KERNEL]);
		fprintf(stdout, "%s      %7d %10d %10d\n", _("all"),
			freps[i]->count[FR_ALL],
			(freps[i]->min[FR_ALL] < 0) ? 0 : freps[i]->min[FR_ALL],
			freps[i]->max[FR_ALL]);
	    }
	}
	break;

    case (O_PRN):
	while ((type = Vect_read_next_line(&In, Points, Cats)) > 0) {
	    id++;
	    int has = 0;

	    if (!(type & otype))
		continue;

	    if (Clist && Vect_cat_in_cat_list(id, Clist) == FALSE)
		continue;

	    /* Check if the line has at least one cat */
	    for (i = 0; i < nfields; i++) {
		for (j = 0; j < Cats->n_cats; j++) {
		    if (Cats->field[j] == fields[i]) {
			has = 1;
			break;
		    }
		}
	    }

	    if (!has)
		continue;

	    for (i = 0; i < nfields; i++) {
		int first = 1;

		if (i > 0)
		    fprintf(stdout, "|");
		for (j = 0; j < Cats->n_cats; j++) {
		    if (Cats->field[j] == fields[i]) {
			if (!first)
			    fprintf(stdout, "/");
			fprintf(stdout, "%d", Cats->cat[j]);
			first = 0;
		    }
		}
	    }
	    fprintf(stdout, "\n");
	}
	break;
    }

    if (option == O_ADD || option == O_DEL || option == O_CHFIELD ||
        option == O_SUM || option == O_TRANS){
        if (!notab->answer){
	    G_message(_("Copying attribute table(s)..."));
            if (Vect_copy_tables(&In, &Out, 0))
                G_warning(_("Failed to copy attribute table to output map"));
	}
	Vect_build(&Out);
	Vect_close(&Out);
    }

    if (option == O_TRANS && nmodified > 0)
        for(i = 1; i < nfields; i++)
	    G_important_message(_("Categories copied from layer %d to layer %d"),
		                  fields[0], fields[i]);

    if (option != O_REP && option != O_PRN) 
        G_done_msg(n_("%d feature modified.",
                      "%d features modified.",
                      nmodified), nmodified);
    
    Vect_close(&In);

    exit(EXIT_SUCCESS);
}
Example #9
0
File: main.c Project: caomw/grass
int main(int argc, char *argv[])
{
    struct GModule *module;
    struct Map_info Map;

    FILE *ascii, *att;
    char *input, *output, *delim, **columns, *where, *field_name, *cats;
    int format, dp, field, ret, region, old_format, header, type;
    int ver, pnt;

    struct cat_list *clist;
    
    clist = NULL;
    
    G_gisinit(argv[0]);

    module = G_define_module();
    G_add_keyword(_("vector"));
    G_add_keyword(_("export"));
    G_add_keyword("ASCII");
    module->label =
	_("Exports a vector map to a GRASS ASCII vector representation.");
    module->description = _("By default only features with category are exported. "
                            "To export all features use 'layer=-1'.");

    parse_args(argc, argv, &input, &output, &format, &dp, &delim,
	       &field_name, &columns, &where, &region, &old_format, &header,
	       &cats, &type);
    
    if (format == GV_ASCII_FORMAT_STD && columns) {
      G_warning(_("Parameter '%s' ignored in standard mode"), "column");
    }

    ver = 5;
    pnt = 0;
    if (old_format)
	ver = 4;
    
    if (ver == 4 && format == GV_ASCII_FORMAT_POINT) {
      G_fatal_error(_("Format '%s' is not supported for old version"), "point");
    }
    
    if (ver == 4 && strcmp(output, "-") == 0) {
        G_fatal_error(_("Parameter '%s' must be given for old version"), "output");
    }

    /* open with topology only if needed */
    if (format == GV_ASCII_FORMAT_WKT ||
        (format == GV_ASCII_FORMAT_STD && (where || clist))) {
	if (Vect_open_old2(&Map, input, "", field_name) < 2) /* topology required for areas */
	    G_warning(_("Unable to open vector map <%s> at topology level. "
			"Areas will not be processed."),
		      input);
    }
    else {
	Vect_set_open_level(1); /* topology not needed */ 
	if (Vect_open_old2(&Map, input, "", field_name) < 0) 
	    G_fatal_error(_("Unable to open vector map <%s>"), input); 
        if (Vect_maptype(&Map) != GV_FORMAT_NATIVE) {
            /* require topological level for external formats
               centroids are read from topo */
            Vect_close(&Map);
            Vect_set_open_level(2);
            if (Vect_open_old2(&Map, input, "", field_name) < 0) 
                G_fatal_error(_("Unable to open vector map <%s>"), input); 
        }
    }

    field = Vect_get_field_number(&Map, field_name);
    if (cats) {
        clist = Vect_new_cat_list();
        
        clist->field = field;
        if (clist->field < 1)
            G_fatal_error(_("Layer <%s> not found"), field_name);
        ret = Vect_str_to_cat_list(cats, clist);
        if (ret > 0)
            G_fatal_error(_n("%d error in <%s> option",
                             "%d errors in <%s> option",
                             ret),
                          ret, "cats");
    }

    if (strcmp(output, "-") != 0) {
	if (ver == 4) {
	    ascii = G_fopen_new("dig_ascii", output);
	}
	else if (strcmp(output, "-") == 0) {
	    ascii = stdout;
	}
	else {
	    ascii = fopen(output, "w");
	}

	if (ascii == NULL) {
	    G_fatal_error(_("Unable to open file <%s>"), output);
	}
    }
    else {
	ascii = stdout;
    }

    if (format == GV_ASCII_FORMAT_STD) {
	Vect_write_ascii_head(ascii, &Map);
	fprintf(ascii, "VERTI:\n");
    }

    /* Open dig_att */
    att = NULL;
    if (ver == 4 && !pnt) {
	if (G_find_file("dig_att", output, G_mapset()) != NULL)
	    G_fatal_error(_("dig_att file already exist"));

	if ((att = G_fopen_new("dig_att", output)) == NULL)
	    G_fatal_error(_("Unable to open dig_att file <%s>"),
			  output);
    }

    if (where || columns || clist)
	G_message(_("Fetching data..."));
    ret = Vect_write_ascii(ascii, att, &Map, ver, format, dp, delim,
			   region, type, field, clist, (const char *)where,
			   (const char **)columns, header);

    if (ret < 1) {
	if (format == GV_ASCII_FORMAT_POINT) {
	    G_warning(_("No points found, nothing to be exported"));
	}
	else {
	    G_warning(_("No features found, nothing to be exported"));
	}
    }
    
    if (ascii != NULL)
	fclose(ascii);
    if (att != NULL)
	fclose(att);

    Vect_close(&Map);

    if (cats)
        Vect_destroy_cat_list(clist);
    
    exit(EXIT_SUCCESS);
}
Example #10
0
void parse_args(int argc, char **argv,
		char **input, char**output, int *format, int *dp, char **delim,
		char **field, char ***columns, char **where, int *region,
		int *old_format, int *header, struct cat_list **clist)
{
    struct Option *input_opt, *output_opt, *format_opt, *dp_opt, *delim_opt,
	*field_opt, *column_opt, *where_opt, *cats_opt;
    struct Flag *old_flag, *header_flag, *region_flag;
    
    input_opt = G_define_standard_option(G_OPT_V_INPUT);

    field_opt = G_define_standard_option(G_OPT_V_FIELD);
    field_opt->guisection = _("Selection");
    
    output_opt = G_define_standard_option(G_OPT_F_OUTPUT);
    output_opt->label = _("Name for output ASCII file "
			  "or ASCII vector name if '-o' is defined");
    output_opt->description = _("'-' for standard output");
    output_opt->required = NO;
    output_opt->answer = "-";

    column_opt = G_define_standard_option(G_OPT_DB_COLUMNS);
    column_opt->description = _("Name of attribute column(s) to be exported (point mode)");
    column_opt->guisection = _("Points");
    
    cats_opt = G_define_standard_option(G_OPT_V_CATS);
    cats_opt->guisection = _("Selection");
    
    where_opt = G_define_standard_option(G_OPT_DB_WHERE);
    where_opt->guisection = _("Selection");

    format_opt = G_define_option();
    format_opt->key = "format";
    format_opt->type = TYPE_STRING;
    format_opt->required = YES;
    format_opt->multiple = NO;
    format_opt->options = "point,standard,wkt";
    format_opt->answer = "point";
    format_opt->description = _("Output format");
    format_opt->descriptions = _("point;Simple point format (point per row);"
				 "standard;GRASS ASCII vector format;"
				 "wkt;OGC well-known text;");

    delim_opt = G_define_standard_option(G_OPT_F_SEP);
    delim_opt->description = _("Field separator (points mode)");
    delim_opt->guisection = _("Points");
    
    dp_opt = G_define_option();
    dp_opt->key = "dp";
    dp_opt->type = TYPE_INTEGER;
    dp_opt->required = NO;
    dp_opt->options = "0-32";
    dp_opt->answer = "8";	/* This value is taken from the lib settings in G_format_easting() */
    dp_opt->description =
	_("Number of significant digits (floating point only)");
    dp_opt->guisection = _("Points");
    
    old_flag = G_define_flag();
    old_flag->key = 'o';
    old_flag->description = _("Create old (version 4) ASCII file");

    header_flag = G_define_flag();
    header_flag->key = 'c';
    header_flag->description = _("Include column names in output (points mode)");
    header_flag->guisection = _("Points");

    region_flag = G_define_flag();
    region_flag->key = 'r';
    region_flag->description =
	_("Only export points falling within current 3D region (points mode)");
    region_flag->guisection = _("Points");

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

    *input = G_store(input_opt->answer);
    *output = G_store(output_opt->answer);
    if (format_opt->answer[0] == 'p')
	*format = GV_ASCII_FORMAT_POINT;
    else if (format_opt->answer[0] == 's')
	*format = GV_ASCII_FORMAT_STD;
    else
	*format = GV_ASCII_FORMAT_WKT;
    if (sscanf(dp_opt->answer, "%d", dp) != 1)
	G_fatal_error(_("Failed to interpret 'dp' parameter as an integer"));
    /* the field separator */
    if (strcmp(delim_opt->answer, "\\t") == 0)
	*delim = G_store("\t");
    else if (strcmp(delim_opt->answer, "tab") == 0)
	*delim = G_store("\t");
    else if (strcmp(delim_opt->answer, "space") == 0)
	*delim = G_store(" ");
    else if (strcmp(delim_opt->answer, "comma") == 0)
	*delim = G_store(",");
    else
	*delim = G_store(delim_opt->answer);
    
    *field = G_store(field_opt->answer);
    *columns = NULL;
    if (column_opt->answer) {
	int i, nopt;
	nopt = 0;
	while(column_opt->answers[nopt++])
	    ;
	*columns = (char **) G_malloc(nopt * sizeof(char *));
	for (i = 0; i < nopt - 1; i++)
	    (*columns)[i] = G_store(column_opt->answers[i]);
	(*columns)[nopt - 1] = NULL;
    }
    *where = NULL;
    if (where_opt->answer) {
	*where = G_store(where_opt->answer);
    }
    *clist = NULL;
    if (cats_opt->answer) {
	int ret;
	
	*clist = Vect_new_cat_list();
	(*clist)->field = atoi(field_opt->answer);
	if ((*clist)->field < 1)
	    G_fatal_error(_("Option <%s> must be > 0"), field_opt->key);
	ret = Vect_str_to_cat_list(cats_opt->answer, *clist);
	if (ret > 0)
	    G_fatal_error(_("%d errors in cat option"), ret);
    }
    *region = region_flag->answer ? 1 : 0;
    *old_format = old_flag->answer ? 1 : 0;
    *header = header_flag->answer ? 1 : 0;
}
Example #11
0
int main(int argc, char **argv)
{
    int i, j, k, ret;
    int nlines, type, ltype, afield, tfield, geo, cat;
    int sp, nsp, nspused, node, line;
    struct Option *map, *output, *afield_opt, *tfield_opt, *afcol, *type_opt,
	*term_opt, *nsp_opt;
    struct Flag *geo_f;
    struct GModule *module;
    struct Map_info Map, Out;
    int *testnode;		/* array all nodes: 1 - should be tested as Steiner, 
				 * 0 - no need to test (unreachable or terminal) */
    struct ilist *TList;	/* list of terminal nodes */
    struct ilist *StArcs;	/* list of arcs on Steiner tree */
    struct ilist *StNodes;	/* list of nodes on Steiner tree */
    struct boxlist *pointlist;
    double cost, tmpcost;
    struct cat_list *Clist;
    struct line_cats *Cats;
    struct line_pnts *Points;
    
    /* Initialize the GIS calls */
    G_gisinit(argv[0]);

    module = G_define_module();
    G_add_keyword(_("vector"));
    G_add_keyword(_("network"));
    G_add_keyword(_("steiner tree"));
    module->label =
	_("Creates Steiner tree for the network and given terminals.");
    module->description =
	_("Note that 'Minimum Steiner Tree' problem is NP-hard "
	  "and heuristic algorithm is used in this module so "
	  "the result may be sub optimal.");

    map = G_define_standard_option(G_OPT_V_INPUT);
    output = G_define_standard_option(G_OPT_V_OUTPUT);

    type_opt = G_define_standard_option(G_OPT_V_TYPE);
    type_opt->key = "arc_type";
    type_opt->options = "line,boundary";
    type_opt->answer = "line,boundary";
    type_opt->label = _("Arc type");

    afield_opt = G_define_standard_option(G_OPT_V_FIELD);
    afield_opt->key = "arc_layer";
    afield_opt->answer = "1";
    afield_opt->label = _("Arc layer");

    tfield_opt = G_define_standard_option(G_OPT_V_FIELD);
    tfield_opt->key = "node_layer";
    tfield_opt->answer = "2";
    tfield_opt->label = _("Node layer (used for terminals)");

    afcol = G_define_option();
    afcol->key = "acolumn";
    afcol->type = TYPE_STRING;
    afcol->required = NO;
    afcol->description = _("Arcs' cost column (for both directions)");

    term_opt = G_define_standard_option(G_OPT_V_CATS);
    term_opt->key = "terminal_cats";
    term_opt->required = YES;
    term_opt->description =
	_("Categories of points on terminals (layer is specified by nlayer)");

    nsp_opt = G_define_option();
    nsp_opt->key = "npoints";
    nsp_opt->type = TYPE_INTEGER;
    nsp_opt->required = NO;
    nsp_opt->multiple = NO;
    nsp_opt->answer = "-1";
    nsp_opt->description = _("Number of Steiner points (-1 for all possible)");

    geo_f = G_define_flag();
    geo_f->key = 'g';
    geo_f->description =
	_("Use geodesic calculation for longitude-latitude locations");

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

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

    type = Vect_option_to_types(type_opt);
    afield = atoi(afield_opt->answer);

    TList = Vect_new_list();
    StArcs = Vect_new_list();
    StNodes = Vect_new_list();

    Clist = Vect_new_cat_list();
    tfield = atoi(tfield_opt->answer);
    Vect_str_to_cat_list(term_opt->answer, Clist);

    G_debug(1, "Imput categories:\n");
    for (i = 0; i < Clist->n_ranges; i++) {
	G_debug(1, "%d - %d\n", Clist->min[i], Clist->max[i]);
    }

    if (geo_f->answer)
	geo = 1;
    else
	geo = 0;

    Vect_check_input_output_name(map->answer, output->answer, G_FATAL_EXIT);

    Vect_set_open_level(2);

    if (Vect_open_old(&Map, map->answer, "") < 0)
	G_fatal_error(_("Unable to open vector map <%s>"), map->answer);

    nnodes = Vect_get_num_nodes(&Map);
    nlines = Vect_get_num_lines(&Map);

    /* Create list of terminals based on list of categories */
    for (i = 1; i <= nlines; i++) {
	ltype = Vect_get_line_type(&Map, i);
	if (!(ltype & GV_POINT))
	    continue;

	Vect_read_line(&Map, Points, Cats, i);
	if (!(Vect_cat_get(Cats, tfield, &cat)))
	    continue;
	node = Vect_find_node(&Map, Points->x[0], Points->y[0], Points->z[0], 0, 0);
	if (!node) {
	    G_warning(_("Point is not connected to the network (cat=%d)"), cat);
	    continue;
	}
	if (Vect_cat_in_cat_list(cat, Clist)) {
	    Vect_list_append(TList, node);
	}
    }

    nterms = TList->n_values;
    /* GTC Terminal refers to an Steiner tree endpoint */
    G_message(_("Number of terminals: %d\n"), nterms);

    if (nterms < 2) {
        /* GTC Terminal refers to an Steiner tree endpoint */
        G_fatal_error(_("Not enough terminals (< 2)"));
    }

    /* Number of steiner points */
    nsp = atoi(nsp_opt->answer);
    if (nsp > nterms - 2) {
	nsp = nterms - 2;
	G_warning(_("Requested number of Steiner points > than possible"));
    }
    else if (nsp == -1) {
	nsp = nterms - 2;
    }

    G_message(_("Number of Steiner points set to %d\n"), nsp);

    testnode = (int *)G_malloc((nnodes + 1) * sizeof(int));
    for (i = 1; i <= nnodes; i++)
	testnode[i] = 1;

    /* Alloc arrays of costs for nodes, first node at 1 (0 not used) */
    nodes_costs = (double **)G_malloc((nnodes) * sizeof(double *));
    for (i = 0; i < nnodes; i++) {
	nodes_costs[i] =
	    (double *)G_malloc((nnodes - i) * sizeof(double));
	for (j = 0; j < nnodes - i; j++)
	    nodes_costs[i][j] = -1;	/* init, i.e. cost was not calculated yet */
    }

    /* alloc memory from each to each other (not directed) terminal */
    i = nterms + nterms - 2;	/*  max number of terms + Steiner points */
    comps = (int *)G_malloc(i * sizeof(int));
    i = i * (i - 1) / 2;	/* number of combinations */
    term_costs = (COST *) G_malloc(i * sizeof(COST));

    /* alloc memory for costs from Stp to each other terminal */
    i = nterms + nterms - 2 - 1;	/*  max number of terms + Steiner points - 1 */
    sp_costs = (COST *) G_malloc(i * sizeof(COST));

    terms = (int *)G_malloc((nterms + nterms - 2) * sizeof(int));	/* i.e. +(nterms - 2)  St Points */
    /* Create initial parts from list of terminals */
    G_debug(1, "List of terminal nodes (%d):\n", nterms);
    for (i = 0; i < nterms; i++) {
	G_debug(1, "%d\n", TList->value[i]);
	terms[i] = TList->value[i];
	testnode[terms[i]] = 0;	/* do not test as Steiner */
    }

    /* Build graph */
    Vect_net_build_graph(&Map, type, afield, 0, afcol->answer, NULL, NULL,
			 geo, 0);

    /* Init costs for all terminals */
    for (i = 0; i < nterms; i++)
	init_node_costs(&Map, terms[i]);

    /* Test if all terminal may be connected */
    for (i = 1; i < nterms; i++) {
	ret = get_node_costs(terms[0], terms[i], &cost);
	if (ret == 0) {
            /* GTC Terminal refers to an Steiner tree endpoint */
	    G_fatal_error(_("Terminal at node [%d] cannot be connected "
			    "to terminal at node [%d]"), terms[0], terms[i]);
	}
    }

    /* Remove not reachable from list of SP candidates */
    j = 0;
    for (i = 1; i <= nnodes; i++) {
	ret = get_node_costs(terms[0], i, &cost);
	if (ret == 0) {
	    testnode[i] = 0;
	    G_debug(2, "node %d removed from list of Steiner point candidates\n", i );
	    j++;
	}
    }

    G_message(_("[%d] (not reachable) nodes removed from list "
		"of Steiner point candidates"), j);

    /* calc costs for terminals MST */
    ret = mst(&Map, terms, nterms, &cost, PORT_DOUBLE_MAX, NULL, NULL, 0, 1);	/* no StP, rebuild */
    G_message(_("MST costs = %f"), cost);

    /* Go through all nodes and try to use as steiner points -> find that which saves most costs */
    nspused = 0;
    for (j = 0; j < nsp; j++) {
	sp = 0;
	G_verbose_message(_("Search for [%d]. Steiner point"), j + 1);

	for (i = 1; i <= nnodes; i++) {
	    G_percent(i, nnodes, 1);
	    if (testnode[i] == 0) {
		G_debug(3, "skip test for %d\n", i);
		continue;
	    }
	    ret =
		mst(&Map, terms, nterms + j, &tmpcost, cost, NULL, NULL, i,
		    0);
	    G_debug(2, "cost = %f x %f\n", tmpcost, cost);
	    if (tmpcost < cost) {	/* sp candidate */
		G_debug(3,
			"  steiner candidate node = %d mst = %f (x last = %f)\n",
			i, tmpcost, cost);
		sp = i;
		cost = tmpcost;
	    }
	}
	if (sp > 0) {
	    G_message(_("Steiner point at node [%d] was added "
			"to terminals (MST costs = %f)"), sp, cost);
	    terms[nterms + j] = sp;
	    init_node_costs(&Map, sp);
	    testnode[sp] = 0;
	    nspused++;
	    /* rebuild for nex cycle */
	    ret =
		mst(&Map, terms, nterms + nspused, &tmpcost, PORT_DOUBLE_MAX,
		    NULL, NULL, 0, 1);
	}
	else {			/* no steiner found */
	    G_message(_("No Steiner point found -> leaving cycle"));
	    break;
	}
    }

    G_message(_("Number of added Steiner points: %d "
	    "(theoretic max is %d).\n"), nspused, nterms - 2);

    /* Build lists of arcs and nodes for final version */
    ret =
	mst(&Map, terms, nterms + nspused, &cost, PORT_DOUBLE_MAX, StArcs,
	    StNodes, 0, 0);

    /* Calculate true costs, which may be lower than MST if steiner points were not used */

    if (nsp < nterms - 2) {
        G_message(_("Spanning tree costs on complet graph = %f\n"
            "(may be higher than resulting Steiner tree costs!!!)"),
		cost);
    }
    else
        G_message(_("Steiner tree costs = %f"), cost);

    /* Write arcs to new map */
    if (Vect_open_new(&Out, output->answer, Vect_is_3d(&Map)) < 0)
	G_fatal_error(_("Unable to create vector map <%s>"), output->answer);

    Vect_hist_command(&Out);

    G_debug(1, "Steiner tree:");
    G_debug(1, "Arcs' categories (layer %d, %d arcs):", afield,
	    StArcs->n_values);
    
    for (i = 0; i < StArcs->n_values; i++) {
	line = StArcs->value[i];
	ltype = Vect_read_line(&Map, Points, Cats, line);
	Vect_write_line(&Out, ltype, Points, Cats);
	Vect_cat_get(Cats, afield, &cat);
        G_debug(1, "arc cat = %d", cat);
    }
    
    G_debug(1, "Nodes' categories (layer %d, %d nodes):", tfield,
	    StNodes->n_values);

    k = 0;
    pointlist = Vect_new_boxlist(0);
    for (i = 0; i < StNodes->n_values; i++) {
	double x, y, z;
	struct bound_box box;
	
	node = StNodes->value[i];
	
	Vect_get_node_coor(&Map, node, &x, &y, &z);
	box.E = box.W = x;
	box.N = box.S = y;
	box.T = box.B = z;
	Vect_select_lines_by_box(&Map, &box, GV_POINT, pointlist);
	
	nlines = Vect_get_node_n_lines(&Map, node);
	for (j = 0; j < pointlist->n_values; j++) {
	    line = pointlist->id[j];
	    ltype = Vect_read_line(&Map, Points, Cats, line);
	    if (!(ltype & GV_POINT))
		continue;
	    if (!(Vect_cat_get(Cats, tfield, &cat)))
		continue;
	    Vect_write_line(&Out, ltype, Points, Cats);
	    G_debug(1, "node cat = %d", cat);
	    k++;
	}
    }

    Vect_build(&Out);

    G_message(n_("A Steiner tree with %d arc has been built",
            "A Steiner tree with %d arcs has been built", StArcs->n_values),
        StArcs->n_values);
    
    /* Free, ... */
    Vect_destroy_list(StArcs);
    Vect_destroy_list(StNodes);
    Vect_close(&Map);
    Vect_close(&Out);

    exit(EXIT_SUCCESS);
}
Example #12
0
/*!
   \brief Set category constraints using 'where' or 'cats' option and layer number.

   \param Map pointer to Map_info structure
   \param layer layer number
   \param where where statement
   \param catstr category list as string

   \return pointer to cat_list structure or NULL
 */
struct cat_list *Vect_cats_set_constraint(struct Map_info *Map, int layer,
                                         char *where, char *catstr)
{
    struct cat_list *list = NULL;
    int ret;

    if (layer < 1) {
	G_warning(_("Layer number must be > 0 for category constraints"));
	/* no valid constraints, all categories qualify */
	return list;
    }

    /* where has precedence over cats */
    if (where) {
	struct field_info *Fi = NULL;
	dbDriver *driver = NULL;
	int ncats, *cats = NULL;
	int i, j;

	if (catstr)
	    G_warning(_("'%s' and '%s' parameters were supplied, cats will be ignored"), "where", "cats");

	Fi = Vect_get_field(Map, layer);
	if (!Fi) {
	    G_fatal_error(_("Database connection not defined for layer %d"),
			  layer);
	}

	G_verbose_message(_("Loading categories from table <%s>..."), Fi->table);

	driver = db_start_driver_open_database(Fi->driver, Fi->database);
	if (driver == NULL)
	    G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
			  Fi->database, Fi->driver);
	
	ncats = db_select_int(driver, Fi->table, Fi->key, where,
			      &cats);
	if (ncats == -1)
		G_fatal_error(_("Unable select records from table <%s>"),
			      Fi->table);
	G_verbose_message(n_("One category loaded", "%d categories loaded", ncats), ncats);
	    
	db_close_database_shutdown_driver(driver);

	/* sort */
	qsort(cats, ncats, sizeof(int), cmp);
	
	/* remove duplicates */
	j = 1;
	for (i = 1; i < ncats; i++) {
	    if (cats[i] != cats[j - 1]) {
		cats[j] = cats[i];
		j++;
	    }
	}
	ncats = j;
	
	/* convert to cat list */
	list = Vect_new_cat_list();
	
	ret = Vect_array_to_cat_list(cats, ncats, list);
	if (ret == 0)
	    G_warning(_("No categories selected with '%s' option"), "where");
	
	if (cats)
	    G_free(cats);
    }
    else if (catstr) {
	list = Vect_new_cat_list();

	ret = Vect_str_to_cat_list(catstr, list);
	if (ret > 0)
	    G_warning(_("%d errors in '%s' option"), ret, "cats");
    }
    
    if (list) {
	if (list->n_ranges < 1) {
	    Vect_destroy_cat_list(list);
	    list = NULL;
	}
	else
	    list->field = layer;
    }
	
    return list;
}
Example #13
0
int main(int argc, char **argv)
{
    int i, j, ret, centre, line, centre1, centre2;
    int nlines, nnodes, type, ltype, afield, nfield, geo, cat;
    int node, node1, node2;
    double cost, e1cost, e2cost, n1cost, n2cost, s1cost, s2cost, l, l1, l2;
    struct Option *map, *output;
    struct Option *afield_opt, *nfield_opt, *afcol, *abcol, *ncol, *type_opt,
	*term_opt;
    struct Flag *geo_f;
    struct GModule *module;
    char *mapset;
    struct Map_info Map, Out;
    struct cat_list *catlist;
    CENTER *Centers = NULL;
    int acentres = 0, ncentres = 0;
    NODE *Nodes;
    struct line_cats *Cats;
    struct line_pnts *Points, *SPoints;

    G_gisinit(argv[0]);

    module = G_define_module();
    module->keywords = _("vector, network, allocation");
    module->label =
	_("Allocate subnets for nearest centres (direction from centre).");
    module->description =
	_("Centre node must be opened (costs >= 0). "
	  "Costs of centre node are used in calculation");


    map = G_define_standard_option(G_OPT_V_INPUT);
    output = G_define_standard_option(G_OPT_V_OUTPUT);

    type_opt = G_define_standard_option(G_OPT_V_TYPE);
    type_opt->options = "line,boundary";
    type_opt->answer = "line,boundary";
    type_opt->description = _("Arc type");

    afield_opt = G_define_standard_option(G_OPT_V_FIELD);
    afield_opt->key = "alayer";
    afield_opt->answer = "1";
    afield_opt->description = _("Arc layer");

    nfield_opt = G_define_standard_option(G_OPT_V_FIELD);
    nfield_opt->key = "nlayer";
    nfield_opt->answer = "2";
    nfield_opt->description = _("Node layer");

    afcol = G_define_option();
    afcol->key = "afcolumn";
    afcol->type = TYPE_STRING;
    afcol->required = NO;
    afcol->description =
	_("Arc forward/both direction(s) cost column (number)");

    abcol = G_define_option();
    abcol->key = "abcolumn";
    abcol->type = TYPE_STRING;
    abcol->required = NO;
    abcol->description = _("Arc backward direction cost column (number)");

    ncol = G_define_option();
    ncol->key = "ncolumn";
    ncol->type = TYPE_STRING;
    ncol->required = NO;
    ncol->description = _("Node cost column (number)");

    term_opt = G_define_standard_option(G_OPT_V_CATS);
    term_opt->key = "ccats";
    term_opt->required = YES;
    term_opt->description =
	_("Categories of centres (points on nodes) to which net "
	  "will be allocated, "
	  "layer for this categories is given by nlayer option");

    geo_f = G_define_flag();
    geo_f->key = 'g';
    geo_f->description =
	_("Use geodesic calculation for longitude-latitude locations");

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

    Vect_check_input_output_name(map->answer, output->answer, GV_FATAL_EXIT);

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

    type = Vect_option_to_types(type_opt);
    afield = atoi(afield_opt->answer);
    nfield = atoi(nfield_opt->answer);

    catlist = Vect_new_cat_list();
    Vect_str_to_cat_list(term_opt->answer, catlist);

    if (geo_f->answer)
	geo = 1;
    else
	geo = 0;

    mapset = G_find_vector2(map->answer, NULL);

    if (mapset == NULL)
	G_fatal_error(_("Vector map <%s> not found"), map->answer);

    Vect_set_open_level(2);
    Vect_open_old(&Map, map->answer, mapset);

    /* Build graph */
    Vect_net_build_graph(&Map, type, afield, nfield, afcol->answer,
			 abcol->answer, ncol->answer, geo, 0);

    nnodes = Vect_get_num_nodes(&Map);

    /* Create list of centres based on list of categories */
    for (node = 1; node <= nnodes; node++) {
	nlines = Vect_get_node_n_lines(&Map, node);
	for (j = 0; j < nlines; j++) {
	    line = abs(Vect_get_node_line(&Map, node, j));
	    ltype = Vect_read_line(&Map, NULL, Cats, line);
	    if (!(ltype & GV_POINT))
		continue;
	    if (!(Vect_cat_get(Cats, nfield, &cat)))
		continue;
	    if (Vect_cat_in_cat_list(cat, catlist)) {
		Vect_net_get_node_cost(&Map, node, &n1cost);
		if (n1cost == -1) {	/* closed */
		    G_warning("Centre at closed node (costs = -1) ignored");
		}
		else {
		    if (acentres == ncentres) {
			acentres += 1;
			Centers =
			    (CENTER *) G_realloc(Centers,
						 acentres * sizeof(CENTER));
		    }
		    Centers[ncentres].cat = cat;
		    Centers[ncentres].node = node;
		    G_debug(2, "centre = %d node = %d cat = %d", ncentres,
			    node, cat);
		    ncentres++;
		}
	    }
	}
    }

    G_message(_("Number of centres: [%d] (nlayer: [%d])"), ncentres, nfield);

    if (ncentres == 0)
	G_warning(_("Not enough centres for selected nlayer. "
		    "Nothing will be allocated."));

    /* alloc and reset space for all nodes */
    Nodes = (NODE *) G_calloc((nnodes + 1), sizeof(NODE));
    for (i = 1; i <= nnodes; i++) {
	Nodes[i].centre = -1;
    }


    /* Fill Nodes by neares centre and costs from that centre */
    G_message(_("Calculating costs from centres ..."));

    for (centre = 0; centre < ncentres; centre++) {
	G_percent(centre, ncentres, 1);
	node1 = Centers[centre].node;
	Vect_net_get_node_cost(&Map, node1, &n1cost);
	G_debug(2, "centre = %d node = %d cat = %d", centre, node1,
		Centers[centre].cat);
	for (node2 = 1; node2 <= nnodes; node2++) {
	    G_debug(5, "  node1 = %d node2 = %d", node1, node2);
	    Vect_net_get_node_cost(&Map, node2, &n2cost);
	    if (n2cost == -1) {
		continue;
	    }			/* closed, left it as not attached */

	    ret = Vect_net_shortest_path(&Map, node1, node2, NULL, &cost);
	    if (ret == -1) {
		continue;
	    }			/* node unreachable */

	    /* We must add centre node costs (not calculated by Vect_net_shortest_path() ), but
	     *  only if centre and node are not identical, because at the end node cost is add later */
	    if (node1 != node2)
		cost += n1cost;

	    G_debug(5,
		    "Arc nodes: %d %d cost: %f (x old cent: %d old cost %f",
		    node1, node2, cost, Nodes[node2].centre,
		    Nodes[node2].cost);
	    if (Nodes[node2].centre == -1 || cost < Nodes[node2].cost) {
		Nodes[node2].cost = cost;
		Nodes[node2].centre = centre;
	    }
	}
    }
    G_percent(1, 1, 1);

    /* Write arcs to new map */
    Vect_open_new(&Out, output->answer, Vect_is_3d(&Map));
    Vect_hist_command(&Out);

    nlines = Vect_get_num_lines(&Map);
    for (line = 1; line <= nlines; line++) {
	ltype = Vect_read_line(&Map, Points, NULL, line);
	if (!(ltype & type)) {
	    continue;
	}
	Vect_get_line_nodes(&Map, line, &node1, &node2);
	centre1 = Nodes[node1].centre;
	centre2 = Nodes[node2].centre;
	s1cost = Nodes[node1].cost;
	s2cost = Nodes[node2].cost;
	G_debug(3, "Line %d:", line);
	G_debug(3, "Arc centres: %d %d (nodes: %d %d)", centre1, centre2,
		node1, node2);

	Vect_net_get_node_cost(&Map, node1, &n1cost);
	Vect_net_get_node_cost(&Map, node2, &n2cost);

	Vect_net_get_line_cost(&Map, line, GV_FORWARD, &e1cost);
	Vect_net_get_line_cost(&Map, line, GV_BACKWARD, &e2cost);

	G_debug(3, "  s1cost = %f n1cost = %f e1cost = %f", s1cost, n1cost,
		e1cost);
	G_debug(3, "  s2cost = %f n2cost = %f e2cost = %f", s2cost, n2cost,
		e2cost);

	Vect_reset_cats(Cats);

	/* First check if arc is reachable from at least one side */
	if ((centre1 != -1 && n1cost != -1 && e1cost != -1) ||
	    (centre2 != -1 && n2cost != -1 && e2cost != -1)) {
	    /* Line is reachable at least from one side */
	    G_debug(3, "  -> arc is reachable");

	    if (centre1 == centre2) {	/* both nodes in one area -> whole arc in one area */
		if (centre1 != -1)
		    cat = Centers[centre1].cat;	/* line reachable */
		else
		    cat = Centers[centre2].cat;
		Vect_cat_set(Cats, 1, cat);
		Vect_write_line(&Out, ltype, Points, Cats);
	    }
	    else {		/* each node in different area */
		/* Check if direction is reachable */
		if (centre1 == -1 || n1cost == -1 || e1cost == -1) {	/* closed from first node */
		    G_debug(3,
			    "    -> arc is not reachable from 1. node -> alloc to 2. node");
		    cat = Centers[centre2].cat;
		    Vect_cat_set(Cats, 1, cat);
		    Vect_write_line(&Out, ltype, Points, Cats);
		    continue;
		}
		else if (centre2 == -1 || n2cost == -1 || e2cost == -1) {	/* closed from second node */
		    G_debug(3,
			    "    -> arc is not reachable from 2. node -> alloc to 1. node");
		    cat = Centers[centre1].cat;
		    Vect_cat_set(Cats, 1, cat);
		    Vect_write_line(&Out, ltype, Points, Cats);
		    continue;
		}

		/* Now we know that arc is reachable from both sides */

		/* Add costs of node to starting costs */
		s1cost += n1cost;
		s2cost += n2cost;

		/* Check if s1cost + e1cost <= s2cost or s2cost + e2cost <= s1cost !
		 * Note this check also possibility of (e1cost + e2cost) = 0 */
		if (s1cost + e1cost <= s2cost) {	/* whole arc reachable from node1 */
		    cat = Centers[centre1].cat;
		    Vect_cat_set(Cats, 1, cat);
		    Vect_write_line(&Out, ltype, Points, Cats);
		}
		else if (s2cost + e2cost <= s1cost) {	/* whole arc reachable from node2 */
		    cat = Centers[centre2].cat;
		    Vect_cat_set(Cats, 1, cat);
		    Vect_write_line(&Out, ltype, Points, Cats);
		}
		else {		/* split */
		    /* Calculate relative costs - we expect that costs along the line do not change */
		    l = Vect_line_length(Points);
		    e1cost /= l;
		    e2cost /= l;

		    G_debug(3, "  -> s1cost = %f e1cost = %f", s1cost,
			    e1cost);
		    G_debug(3, "  -> s2cost = %f e2cost = %f", s2cost,
			    e2cost);

		    /* Costs from both centres to the splitting point must be equal:
		     * s1cost + l1 * e1cost = s2cost + l2 * e2cost */
		    l1 = (l * e2cost - s1cost + s2cost) / (e1cost + e2cost);
		    l2 = l - l1;
		    G_debug(3, "l = %f l1 = %f l2 = %f", l, l1, l2);

		    /* First segment */
		    ret = Vect_line_segment(Points, 0, l1, SPoints);
		    if (ret == 0) {
			G_warning(_("Cannot get line segment, segment out of line"));
		    }
		    else {
			cat = Centers[centre1].cat;
			Vect_cat_set(Cats, 1, cat);
			Vect_write_line(&Out, ltype, SPoints, Cats);
		    }

		    /* Second segment */
		    ret = Vect_line_segment(Points, l1, l, SPoints);
		    if (ret == 0) {
			G_warning(_("Cannot get line segment, segment out of line"));
		    }
		    else {
			Vect_reset_cats(Cats);
			cat = Centers[centre2].cat;
			Vect_cat_set(Cats, 1, cat);
			Vect_write_line(&Out, ltype, SPoints, Cats);
		    }
		}
	    }
	}
	else {
	    /* arc is not reachable */
	    G_debug(3, "  -> arc is not reachable");
	    Vect_write_line(&Out, ltype, Points, Cats);
	}
    }

    Vect_build(&Out);

    /* Free, ... */
    G_free(Nodes);
    G_free(Centers);
    Vect_close(&Map);
    Vect_close(&Out);

    exit(EXIT_SUCCESS);
}
Example #14
0
int main(int argc, char **argv)
{
    int i, j, k, ret, city, city1;
    int nlines, type, ltype, afield, tfield, geo, cat;
    int node, node1, node2, line;
    struct Option *map, *output, *afield_opt, *tfield_opt, *afcol, *type_opt,
	*term_opt;
    struct Flag *geo_f;
    struct GModule *module;
    char *mapset;
    struct Map_info Map, Out;
    struct ilist *TList;	/* list of terminal nodes */
    struct ilist *List;
    struct ilist *StArcs;	/* list of arcs on Steiner tree */
    struct ilist *StNodes;	/* list of nodes on Steiner tree */
    double cost, tmpcost, tcost;
    struct cat_list *Clist;
    struct line_cats *Cats;
    struct line_pnts *Points;

    /* Initialize the GIS calls */
    G_gisinit(argv[0]);

    module = G_define_module();
    module->keywords = _("vector, network, salesman");
    module->label =
	_("Creates a cycle connecting given nodes (Traveling salesman problem).");
    module->description =
	_("Note that TSP is NP-hard, heuristic algorithm is used by "
	  "this module and created cycle may be sub optimal");

    map = G_define_standard_option(G_OPT_V_INPUT);
    output = G_define_standard_option(G_OPT_V_OUTPUT);

    type_opt = G_define_standard_option(G_OPT_V_TYPE);
    type_opt->options = "line,boundary";
    type_opt->answer = "line,boundary";
    type_opt->description = _("Arc type");

    afield_opt = G_define_standard_option(G_OPT_V_FIELD);
    afield_opt->key = "alayer";
    afield_opt->description = _("Arc layer");

    tfield_opt = G_define_standard_option(G_OPT_V_FIELD);
    tfield_opt->key = "nlayer";
    tfield_opt->answer = "2";
    tfield_opt->description = _("Node layer (used for cities)");

    afcol = G_define_option();
    afcol->key = "acolumn";
    afcol->type = TYPE_STRING;
    afcol->required = NO;
    afcol->description = _("Arcs' cost column (for both directions)");

    term_opt = G_define_standard_option(G_OPT_V_CATS);
    term_opt->key = "ccats";
    term_opt->required = YES;
    term_opt->description = _("Categories of points ('cities') on nodes "
			      "(layer is specified by nlayer)");

    geo_f = G_define_flag();
    geo_f->key = 'g';
    geo_f->description =
	_("Use geodesic calculation for longitude-latitude locations");

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

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

    type = Vect_option_to_types(type_opt);
    afield = atoi(afield_opt->answer);

    TList = Vect_new_list();
    List = Vect_new_list();
    StArcs = Vect_new_list();
    StNodes = Vect_new_list();

    Clist = Vect_new_cat_list();
    tfield = atoi(tfield_opt->answer);
    Vect_str_to_cat_list(term_opt->answer, Clist);

    G_debug(1, "Imput categories:\n");
    for (i = 0; i < Clist->n_ranges; i++) {
	G_debug(1, "%d - %d\n", Clist->min[i], Clist->max[i]);
    }

    if (geo_f->answer)
	geo = 1;
    else
	geo = 0;

    Vect_check_input_output_name(map->answer, output->answer, GV_FATAL_EXIT);

    mapset = G_find_vector2(map->answer, NULL);

    if (mapset == NULL)
	G_fatal_error(_("Vector map <%s> not found"), map->answer);

    Vect_set_open_level(2);
    Vect_open_old(&Map, map->answer, mapset);
    nnodes = Vect_get_num_nodes(&Map);

    /* Create list of terminals based on list of categories */
    for (i = 1; i <= nnodes; i++) {
	nlines = Vect_get_node_n_lines(&Map, i);
	for (j = 0; j < nlines; j++) {
	    line = abs(Vect_get_node_line(&Map, i, j));
	    ltype = Vect_read_line(&Map, NULL, Cats, line);
	    if (!(ltype & GV_POINT))
		continue;
	    if (!(Vect_cat_get(Cats, tfield, &cat)))
		continue;
	    if (Vect_cat_in_cat_list(cat, Clist)) {
		Vect_list_append(TList, i);
	    }
	}
    }
    ncities = TList->n_values;
    G_message(_("Number of cities: [%d]"), ncities);
    if (ncities < 2)
	G_fatal_error(_("Not enough cities (< 2)"));

    /* Alloc memory */
    cities = (int *)G_malloc(ncities * sizeof(int));
    cused = (int *)G_malloc(ncities * sizeof(int));
    for (i = 0; i < ncities; i++) {
	G_debug(1, "%d\n", TList->value[i]);
	cities[i] = TList->value[i];
	cused[i] = 0;		/* not in cycle */
    }

    costs = (COST **) G_malloc(ncities * sizeof(COST *));
    for (i = 0; i < ncities; i++) {
	costs[i] = (COST *) G_malloc(ncities * sizeof(COST));
    }

    cycle = (int *)G_malloc((ncities + 1) * sizeof(int));	/* + 1 is for output cycle */

    /* Build graph */
    Vect_net_build_graph(&Map, type, afield, 0, afcol->answer, NULL, NULL,
			 geo, 0);

    /* Create sorted lists of costs */
    for (i = 0; i < ncities; i++) {
	k = 0;
	for (j = 0; j < ncities; j++) {
	    if (i == j)
		continue;
	    ret =
		Vect_net_shortest_path(&Map, cities[i], cities[j], NULL,
				       &cost);
	    if (ret == -1)
		G_fatal_error(_("Destination node [%d] is unreachable "
				"from node [%d]"), cities[i], cities[j]);

	    costs[i][k].city = j;
	    costs[i][k].cost = cost;
	    k++;
	}
	qsort((void *)costs[i], k, sizeof(COST), cmp);
    }
    /* debug: print sorted */
    for (i = 0; i < ncities; i++) {
	for (j = 0; j < ncities - 1; j++) {
	    city = costs[i][j].city;
	    G_debug(2, "%d -> %d = %f\n", cities[i], cities[city],
		    costs[i][j].cost);
	}
    }

    /* find 2 cities with largest distance */
    cost = -1;
    for (i = 0; i < ncities; i++) {
	tmpcost = costs[i][ncities - 2].cost;
	if (tmpcost > cost) {
	    cost = tmpcost;
	    city = i;
	}
    }
    G_debug(2, "biggest costs %d - %d\n", city,
	    costs[city][ncities - 2].city);

    /* add this 2 cities to array */
    add_city(city, -1);
    add_city(costs[city][ncities - 2].city, 0);

    /* In each step, find not used city, with biggest cost to any used city, and insert 
     *  into cycle between 2 nearest nodes */
    for (i = 0; i < ncities - 2; i++) {
	cost = -1;
	G_debug(2, "---- %d ----\n", i);
	for (j = 0; j < ncities; j++) {
	    if (cused[j] == 1)
		continue;
	    tmpcost = 0;
	    for (k = 0; k < ncities - 1; k++) {
		G_debug(2, "? %d (%d) - %d (%d) \n", j, cnode(j),
			costs[j][k].city, cnode(costs[j][k].city));
		if (!cused[costs[j][k].city])
		    continue;	/* only used */
		tmpcost += costs[j][k].cost;
		break;		/* first nearest */
	    }
	    G_debug(2, "    cost = %f x %f\n", tmpcost, cost);
	    if (tmpcost > cost) {
		cost = tmpcost;
		city = j;
	    }
	}
	G_debug(2, "add %d\n", city);

	/* add to cycle on lovest costs */
	cycle[ncyc] = cycle[0];	/* tmp for cycle */
	cost = PORT_DOUBLE_MAX;
	for (j = 0; j < ncyc; j++) {
	    node1 = cities[cycle[j]];
	    node2 = cities[cycle[j + 1]];
	    ret = Vect_net_shortest_path(&Map, node1, node2, NULL, &tcost);
	    tmpcost = -tcost;
	    node1 = cities[cycle[j]];
	    node2 = cities[city];
	    ret = Vect_net_shortest_path(&Map, node1, node2, NULL, &tcost);
	    tmpcost += tcost;
	    node1 = cities[cycle[j + 1]];
	    node2 = cities[city];
	    ret = Vect_net_shortest_path(&Map, node1, node2, NULL, &tcost);
	    tmpcost += tcost;

	    G_debug(2, "? %d - %d cost = %f x %f\n", node1, node2, tmpcost,
		    cost);
	    if (tmpcost < cost) {
		city1 = j;
		cost = tmpcost;
	    }
	}

	add_city(city, city1);

    }

    /* Print */
    G_debug(2, "Cycle:\n");
    for (i = 0; i < ncities; i++) {
	G_debug(2, "%d: %d: %d\n", i, cycle[i], cities[cycle[i]]);
    }

    /* Create list of arcs */
    cycle[ncities] = cycle[0];
    for (i = 0; i < ncities; i++) {
	node1 = cities[cycle[i]];
	node2 = cities[cycle[i + 1]];
	G_debug(2, " %d -> %d\n", node1, node2);
	ret = Vect_net_shortest_path(&Map, node1, node2, List, NULL);
	for (j = 0; j < List->n_values; j++) {
	    line = abs(List->value[j]);
	    Vect_list_append(StArcs, line);
	    Vect_get_line_nodes(&Map, line, &node1, &node2);
	    Vect_list_append(StNodes, node1);
	    Vect_list_append(StNodes, node2);
	}
    }



    /* Write arcs to new map */
    Vect_open_new(&Out, output->answer, Vect_is_3d(&Map));
    Vect_hist_command(&Out);

    fprintf(stdout, "\nCycle:\n");
    fprintf(stdout, "Arcs' categories (layer %d, %d arcs):\n", afield,
	    StArcs->n_values);
    for (i = 0; i < StArcs->n_values; i++) {
	line = StArcs->value[i];
	ltype = Vect_read_line(&Map, Points, Cats, line);
	Vect_write_line(&Out, ltype, Points, Cats);
	Vect_cat_get(Cats, afield, &cat);
	if (i > 0)
	    printf(",");
	fprintf(stdout, "%d", cat);
    }
    fprintf(stdout, "\n\n");

    fprintf(stdout, "Nodes' categories (layer %d, %d nodes):\n", tfield,
	    StNodes->n_values);
    k = 0;
    for (i = 0; i < StNodes->n_values; i++) {
	node = StNodes->value[i];
	nlines = Vect_get_node_n_lines(&Map, node);
	for (j = 0; j < nlines; j++) {
	    line = abs(Vect_get_node_line(&Map, node, j));
	    ltype = Vect_read_line(&Map, Points, Cats, line);
	    if (!(ltype & GV_POINT))
		continue;
	    if (!(Vect_cat_get(Cats, tfield, &cat)))
		continue;
	    Vect_write_line(&Out, ltype, Points, Cats);
	    if (k > 0)
		fprintf(stdout, ",");
	    fprintf(stdout, "%d", cat);
	    k++;
	}
    }
    fprintf(stdout, "\n\n");

    Vect_build(&Out);

    /* Free, ... */
    Vect_destroy_list(StArcs);
    Vect_destroy_list(StNodes);
    Vect_close(&Map);
    Vect_close(&Out);

    exit(EXIT_SUCCESS);
}
Example #15
0
int main(int argc, char **argv)
{
    char *mapset;
    int ret, level;
    int i, stat = 0, type, display;
    int chcat = 0;
    int r, g, b;
    int has_color, has_fcolor;
    struct color_rgb color, fcolor;
    double size;
    int default_width;
    double width_scale;
    int verbose = FALSE;
    double minreg, maxreg, reg;
    char map_name[128];
    struct GModule *module;
    struct Option *map_opt;
    struct Option *color_opt, *fcolor_opt, *rgbcol_opt, *zcol_opt;
    struct Option *type_opt, *display_opt;
    struct Option *icon_opt, *size_opt, *sizecolumn_opt, *rotcolumn_opt;
    struct Option *where_opt;
    struct Option *field_opt, *cat_opt, *lfield_opt;
    struct Option *lcolor_opt, *bgcolor_opt, *bcolor_opt;
    struct Option *lsize_opt, *font_opt, *xref_opt, *yref_opt;
    struct Option *attrcol_opt, *maxreg_opt, *minreg_opt;
    struct Option *width_opt, *wcolumn_opt, *wscale_opt;
    struct Option *render_opt;
    struct Flag *verbose_flag;	/* please remove before GRASS 7 released */
    struct Flag *id_flag, *table_acolors_flag, *cats_acolors_flag, *x_flag,
	*zcol_flag;
    struct cat_list *Clist;
    int *cats, ncat;
    LATTR lattr;
    struct Map_info Map;
    struct field_info *fi;
    dbDriver *driver;
    dbHandle handle;
    struct Cell_head window;
    BOUND_BOX box;
    double overlap;

    /* Initialize the GIS calls */
    G_gisinit(argv[0]);

    module = G_define_module();
    module->keywords = _("display, vector");
    module->description = _("Displays user-specified vector map "
			    "in the active graphics frame.");
    
    map_opt = G_define_standard_option(G_OPT_V_MAP);

    display_opt = G_define_option();
    display_opt->key = "display";
    display_opt->type = TYPE_STRING;
    display_opt->required = YES;
    display_opt->multiple = YES;
    display_opt->answer = "shape";
    display_opt->options = "shape,cat,topo,dir,attr,zcoor";
    display_opt->description = _("Display");
    display_opt->descriptions = _("shape;Display geometry of features;"
				  "cat;Display category numbers of features;"
				  "topo;Display topology information (nodes, edges);"
				  "dir;Display direction of linear features;"
				  "attr;Display selected attribute based on 'attrcol';"
				  "zcoor;Display z-coordinate of features (only for 3D vector maps)");
    
    /* Query */
    type_opt = G_define_standard_option(G_OPT_V_TYPE);
    type_opt->answer = "point,line,boundary,centroid,area,face";
    type_opt->options = "point,line,boundary,centroid,area,face";
    type_opt->guisection = _("Selection");

    field_opt = G_define_standard_option(G_OPT_V_FIELD);
    field_opt->label =
	_("Layer number (if -1, all layers are displayed)");
    field_opt->gisprompt = "old_layer,layer,layer_all";
    field_opt->guisection = _("Selection");

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

    where_opt = G_define_standard_option(G_OPT_WHERE);
    where_opt->guisection = _("Selection");

    /* Colors */
    color_opt = G_define_option();
    color_opt->key = "color";
    color_opt->type = TYPE_STRING;
    color_opt->answer = DEFAULT_FG_COLOR;
    color_opt->label = _("Feature color");
    color_opt->guisection = _("Colors");
    color_opt->gisprompt = "old_color,color,color_none";
    color_opt->description =
	_("Either a standard GRASS color, R:G:B triplet, or \"none\"");

    fcolor_opt = G_define_option();
    fcolor_opt->key = "fcolor";
    fcolor_opt->type = TYPE_STRING;
    fcolor_opt->answer = "200:200:200";
    fcolor_opt->label = _("Area fill color");
    fcolor_opt->guisection = _("Colors");
    fcolor_opt->gisprompt = "old_color,color,color_none";
    fcolor_opt->description =
	_("Either a standard GRASS color, R:G:B triplet, or \"none\"");

    rgbcol_opt = G_define_standard_option(G_OPT_COLUMN);
    rgbcol_opt->key = "rgb_column";
    rgbcol_opt->guisection = _("Colors");
    rgbcol_opt->description = _("Name of color definition column (for use with -a flag)");
    rgbcol_opt->answer = "GRASSRGB";

    zcol_opt = G_define_option();
    zcol_opt->key = "zcolor";
    zcol_opt->key_desc = "style";
    zcol_opt->type = TYPE_STRING;
    zcol_opt->required = NO;
    zcol_opt->description = _("Type of color table (for use with -z flag)");
    zcol_opt->answer = "terrain";
    zcol_opt->guisection = _("Colors");

    /* Lines */
    width_opt = G_define_option();
    width_opt->key = "width";
    width_opt->type = TYPE_INTEGER;
    width_opt->answer = "0";
    width_opt->guisection = _("Lines");
    width_opt->description = _("Line width");

    wcolumn_opt = G_define_standard_option(G_OPT_COLUMN);
    wcolumn_opt->key = "wcolumn";
    wcolumn_opt->guisection = _("Lines");
    wcolumn_opt->description =
	_("Name of column for line widths (these values will be scaled by wscale)");

    wscale_opt = G_define_option();
    wscale_opt->key = "wscale";
    wscale_opt->type = TYPE_DOUBLE;
    wscale_opt->answer = "1";
    wscale_opt->guisection = _("Lines");
    wscale_opt->description = _("Scale factor for wcolumn");

    /* Symbols */
    icon_opt = G_define_option();
    icon_opt->key = "icon";
    icon_opt->type = TYPE_STRING;
    icon_opt->required = NO;
    icon_opt->multiple = NO;
    icon_opt->guisection = _("Symbols");
    icon_opt->answer = "basic/x";
    /* This could also use ->gisprompt = "old,symbol,symbol" instead of ->options */
    icon_opt->options = icon_files();
    icon_opt->description = _("Point and centroid symbol");

    size_opt = G_define_option();
    size_opt->key = "size";
    size_opt->type = TYPE_DOUBLE;
    size_opt->answer = "5";
    size_opt->guisection = _("Symbols");
    size_opt->label = _("Symbol size");
    size_opt->description =
	_("When used with the size_column option this becomes the scale factor");

    sizecolumn_opt = G_define_standard_option(G_OPT_COLUMN);
    sizecolumn_opt->key = "size_column";
    sizecolumn_opt->guisection = _("Symbols");
    sizecolumn_opt->description =
	_("Name of numeric column containing symbol size");

    rotcolumn_opt = G_define_standard_option(G_OPT_COLUMN);
    rotcolumn_opt->key = "rot_column";
    rotcolumn_opt->guisection = _("Symbols");
    rotcolumn_opt->label =
	_("Name of numeric column containing symbol rotation angle");
    rotcolumn_opt->description =
	_("Measured in degrees CCW from east");

    /* Labels */
    lfield_opt = G_define_standard_option(G_OPT_V_FIELD);
    lfield_opt->key = "llayer";
    lfield_opt->guisection = _("Labels");
    lfield_opt->description =
	_("Layer number for labels (default: the given layer number)");

    attrcol_opt = G_define_standard_option(G_OPT_COLUMN);
    attrcol_opt->key = "attrcol";
    attrcol_opt->multiple = NO;	/* or fix attr.c, around line 102 */
    attrcol_opt->guisection = _("Labels");
    attrcol_opt->description = _("Name of column to be displayed");

    lcolor_opt = G_define_option();
    lcolor_opt->key = "lcolor";
    lcolor_opt->type = TYPE_STRING;
    lcolor_opt->answer = "red";
    lcolor_opt->label = _("Label color");
    lcolor_opt->guisection = _("Labels");
    lcolor_opt->gisprompt = "old_color,color,color";
    lcolor_opt->description = _("Either a standard color name or R:G:B triplet");

    bgcolor_opt = G_define_option();
    bgcolor_opt->key = "bgcolor";
    bgcolor_opt->type = TYPE_STRING;
    bgcolor_opt->answer = "none";
    bgcolor_opt->guisection = _("Labels");
    bgcolor_opt->label = _("Label background color");
    bgcolor_opt->gisprompt = "old_color,color,color_none";
    bgcolor_opt->description =
	_("Either a standard GRASS color, R:G:B triplet, or \"none\"");

    bcolor_opt = G_define_option();
    bcolor_opt->key = "bcolor";
    bcolor_opt->type = TYPE_STRING;
    bcolor_opt->answer = "none";
    bcolor_opt->guisection = _("Labels");
    bcolor_opt->label = _("Label border color");
    bcolor_opt->gisprompt = "old_color,color,color_none";
    bcolor_opt->description =
	_("Either a standard GRASS color, R:G:B triplet, or \"none\"");

    lsize_opt = G_define_option();
    lsize_opt->key = "lsize";
    lsize_opt->type = TYPE_INTEGER;
    lsize_opt->answer = "8";
    lsize_opt->guisection = _("Labels");
    lsize_opt->description = _("Label size (pixels)");

    font_opt = G_define_option();
    font_opt->key = "font";
    font_opt->type = TYPE_STRING;
    font_opt->guisection = _("Labels");
    font_opt->description = _("Font name");

    xref_opt = G_define_option();
    xref_opt->key = "xref";
    xref_opt->type = TYPE_STRING;
    xref_opt->guisection = _("Labels");
    xref_opt->answer = "left";
    xref_opt->options = "left,center,right";
    xref_opt->description = _("Label horizontal justification");

    yref_opt = G_define_option();
    yref_opt->key = "yref";
    yref_opt->type = TYPE_STRING;
    yref_opt->guisection = _("Labels");
    yref_opt->answer = "center";
    yref_opt->options = "top,center,bottom";
    yref_opt->description = _("Label vertical justification");

    minreg_opt = G_define_option();
    minreg_opt->key = "minreg";
    minreg_opt->type = TYPE_DOUBLE;
    minreg_opt->required = NO;
    minreg_opt->description =
	_("Minimum region size (average from height and width) "
	  "when map is displayed");

    maxreg_opt = G_define_option();
    maxreg_opt->key = "maxreg";
    maxreg_opt->type = TYPE_DOUBLE;
    maxreg_opt->required = NO;
    maxreg_opt->description =
	_("Maximum region size (average from height and width) "
	  "when map is displayed");

    render_opt = G_define_option();
    render_opt->key = "render";
    render_opt->type = TYPE_STRING;
    render_opt->required = NO;
    render_opt->multiple = NO;
    render_opt->answer = "c";
    render_opt->options = "g,r,d,c,l";
    render_opt->description = _("Rendering method for filled polygons");
    render_opt->descriptions =
	_("g;use the libgis render functions (features: clipping);"
	  "r;use the raster graphics library functions (features: polylines);"
	  "d;use the display library basic functions (features: polylines);"
	  "c;use the display library clipping functions (features: clipping);"
	  "l;use the display library culling functions (features: culling, polylines)");

    /* please remove before GRASS 7 released */
    verbose_flag = G_define_flag();
    verbose_flag->key = 'v';
    verbose_flag->description = _("Run verbosely");

    /* Colors */
    table_acolors_flag = G_define_flag();
    table_acolors_flag->key = 'a';
    table_acolors_flag->guisection = _("Colors");
    table_acolors_flag->description =
	_("Get colors from map table column (of form RRR:GGG:BBB)");

    cats_acolors_flag = G_define_flag();
    cats_acolors_flag->key = 'c';
    cats_acolors_flag->guisection = _("Colors");
    cats_acolors_flag->description =
	_("Random colors according to category number "
	  "(or layer number if 'layer=-1' is given)");

    /* Query */
    id_flag = G_define_flag();
    id_flag->key = 'i';
    id_flag->guisection = _("Selection");
    id_flag->description = _("Use values from 'cats' option as feature id");

    x_flag = G_define_flag();
    x_flag->key = 'x';
    x_flag->description =
	_("Don't add to list of vectors and commands in monitor "
	  "(it won't be drawn if the monitor is refreshed)");

    zcol_flag = G_define_flag();
    zcol_flag->key = 'z';
    zcol_flag->description = _("Colorize polygons according to z height");
    zcol_flag->guisection = _("Colors");

    /* Check command line */
    if (G_parser(argc, argv))
	exit(EXIT_FAILURE);

    if (G_strcasecmp(render_opt->answer, "g") == 0)
	render = RENDER_GPP;
    else if (G_strcasecmp(render_opt->answer, "r") == 0)
	render = RENDER_RPA;
    else if (G_strcasecmp(render_opt->answer, "d") == 0)
	render = RENDER_DP;
    else if (G_strcasecmp(render_opt->answer, "c") == 0)
	render = RENDER_DPC;
    else if (G_strcasecmp(render_opt->answer, "l") == 0)
	render = RENDER_DPL;
    else
	render = RENDER_GPP;

    /* please remove -v flag before GRASS 7 released */
    if (verbose_flag->answer) {
	G_putenv("GRASS_VERBOSE", "3");
	G_warning(_("The '-v' flag is superseded and will be removed "
		    "in future. Please use '--verbose' instead."));
    }
    /* but keep this */
    if (G_verbose() > G_verbose_std())
	verbose = TRUE;

    G_get_set_window(&window);

    if (R_open_driver() != 0)
	G_fatal_error(_("No graphics device selected"));

    /* Read map options */

    /* Check min/max region */
    reg = ((window.east - window.west) + (window.north - window.south)) / 2;
    if (minreg_opt->answer) {
	minreg = atof(minreg_opt->answer);

	if (reg < minreg) {
	    G_message(_("Region size is lower than minreg, nothing displayed."));
	    D_add_to_list(G_recreate_command());
	    exit(EXIT_SUCCESS);
	}
    }
    if (maxreg_opt->answer) {
	maxreg = atof(maxreg_opt->answer);

	if (reg > maxreg) {
	    G_message(_("Region size is greater than maxreg, nothing displayed."));
	    D_add_to_list(G_recreate_command());
	    exit(EXIT_SUCCESS);
	}
    }

    G_strcpy(map_name, map_opt->answer);

    default_width = atoi(width_opt->answer);
    if (default_width < 0)
	default_width = 0;
    width_scale = atof(wscale_opt->answer);

    if (table_acolors_flag->answer && cats_acolors_flag->answer) {
	cats_acolors_flag->answer = '\0';
	G_warning(_("The '-c' and '-a' flags cannot be used together, "
		    "the '-c' flag will be ignored!"));
    }

    color = G_standard_color_rgb(WHITE);
    ret = G_str_to_color(color_opt->answer, &r, &g, &b);
    if (ret == 1) {
	has_color = 1;
	color.r = r;
	color.g = g;
	color.b = b;
    }
    else if (ret == 2) {	/* none */
	has_color = 0;
    }
    else if (ret == 0) {	/* error */
	G_fatal_error(_("Unknown color: [%s]"), color_opt->answer);
    }

    fcolor = G_standard_color_rgb(WHITE);
    ret = G_str_to_color(fcolor_opt->answer, &r, &g, &b);
    if (ret == 1) {
	has_fcolor = 1;
	fcolor.r = r;
	fcolor.g = g;
	fcolor.b = b;
    }
    else if (ret == 2) {	/* none */
	has_fcolor = 0;
    }
    else if (ret == 0) {	/* error */
	G_fatal_error(_("Unknown color: '%s'"), fcolor_opt->answer);
    }

    size = atof(size_opt->answer);

    /* Make sure map is available */
    mapset = G_find_vector2(map_name, "");

    if (mapset == NULL)
	G_fatal_error(_("Vector map <%s> not found"), map_name);

    /* if where_opt was specified select categories from db 
     * otherwise parse cat_opt */
    Clist = Vect_new_cat_list();
    Clist->field = atoi(field_opt->answer);

    /* open vector */
    level = Vect_open_old(&Map, map_name, mapset);

    if (where_opt->answer) {
	if (Clist->field < 1)
	    G_fatal_error(_("'layer' must be > 0 for 'where'."));
	chcat = 1;
	if ((fi = Vect_get_field(&Map, Clist->field)) == NULL)
	    G_fatal_error(_("Database connection not defined"));
	if (fi != NULL) {
	    driver = db_start_driver(fi->driver);
	    if (driver == NULL)
		G_fatal_error(_("Unable to start driver <%s>"), fi->driver);

	    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>"),
			      fi->database);

	    ncat =
		db_select_int(driver, fi->table, fi->key, where_opt->answer,
			      &cats);

	    db_close_database(driver);
	    db_shutdown_driver(driver);

	    Vect_array_to_cat_list(cats, ncat, Clist);
	}
    }
    else if (cat_opt->answer) {
	if (Clist->field < 1)
	    G_fatal_error(_("'layer' must be > 0 for 'cats'."));
	chcat = 1;
	ret = Vect_str_to_cat_list(cat_opt->answer, Clist);
	if (ret > 0)
	    G_warning(_("%d errors in cat option"), ret);
    }

    type = Vect_option_to_types(type_opt); 

    i = 0;
    display = 0;
    while (display_opt->answers[i]) {
	switch (display_opt->answers[i][0]) {
	case 's':
	    display |= DISP_SHAPE;
	    break;
	case 'c':
	    display |= DISP_CAT;
	    break;
	case 't':
	    display |= DISP_TOPO;
	    break;
	case 'd':
	    display |= DISP_DIR;
	    break;
	case 'a':
	    display |= DISP_ATTR;
	    break;
	case 'z':
	    display |= DISP_ZCOOR;
	    break;
	}
	i++;
    }

    /* Read label options */
    if (lfield_opt->answer != NULL)
	lattr.field = atoi(lfield_opt->answer);
    else
	lattr.field = Clist->field;

    lattr.color.R = lattr.color.G = lattr.color.B = 255;
    if (G_str_to_color(lcolor_opt->answer, &r, &g, &b)) {
	lattr.color.R = r;
	lattr.color.G = g;
	lattr.color.B = b;
    }
    lattr.has_bgcolor = 0;
    if (G_str_to_color(bgcolor_opt->answer, &r, &g, &b) == 1) {
	lattr.has_bgcolor = 1;
	lattr.bgcolor.R = r;
	lattr.bgcolor.G = g;
	lattr.bgcolor.B = b;
    }
    lattr.has_bcolor = 0;
    if (G_str_to_color(bcolor_opt->answer, &r, &g, &b) == 1) {
	lattr.has_bcolor = 1;
	lattr.bcolor.R = r;
	lattr.bcolor.G = g;
	lattr.bcolor.B = b;
    }

    lattr.size = atoi(lsize_opt->answer);
    lattr.font = font_opt->answer;
    switch (xref_opt->answer[0]) {
    case 'l':
	lattr.xref = LLEFT;
	break;
    case 'c':
	lattr.xref = LCENTER;
	break;
    case 'r':
	lattr.xref = LRIGHT;
	break;
    }
    switch (yref_opt->answer[0]) {
    case 't':
	lattr.yref = LTOP;
	break;
    case 'c':
	lattr.yref = LCENTER;
	break;
    case 'b':
	lattr.yref = LBOTTOM;
	break;
    }

    D_setup(0);

    G_setup_plot(D_get_d_north(), D_get_d_south(),
		 D_get_d_west(), D_get_d_east(), D_move_abs, D_cont_abs);

    if (verbose)
	G_message(_("Plotting ..."));

    if (level >= 2)
	Vect_get_map_box(&Map, &box);

    if (level >= 2 && (window.north < box.S || window.south > box.N ||
		       window.east < box.W ||
		       window.west > G_adjust_easting(box.E, &window))) {
	G_message(_("The bounding box of the map is outside the current region, "
		   "nothing drawn."));
	stat = 0;
    }
    else {
	overlap =
	    G_window_percentage_overlap(&window, box.N, box.S, box.E, box.W);
	G_debug(1, "overlap = %f \n", overlap);
	if (overlap < 1)
	    Vect_set_constraint_region(&Map, window.north, window.south,
				       window.east, window.west,
				       PORT_DOUBLE_MAX, -PORT_DOUBLE_MAX);

	/* default line width */
	if (!wcolumn_opt->answer)
	    D_line_width(default_width);

	if (type & GV_AREA) {
	    if (level >= 2) {
		if (display & DISP_SHAPE) {
		    stat = darea(&Map, Clist,
				 has_color ? &color : NULL,
				 has_fcolor ? &fcolor : NULL, chcat,
				 (int)id_flag->answer,
				 table_acolors_flag->answer,
				 cats_acolors_flag->answer, &window,
				 rgbcol_opt->answer, default_width,
				 wcolumn_opt->answer, width_scale,
				 zcol_flag->answer, zcol_opt->answer);
		}
		if (wcolumn_opt->answer)
		    D_line_width(default_width);
	    }
	    else
		G_warning(_("Unable to display areas, topology not available"));
	}

	if (display & DISP_SHAPE) {
	    if (id_flag->answer && level < 2) {
		G_warning(_("Unable to display lines by id, topology not available"));
	    }
	    else {
		stat = plot1(&Map, type, Clist,
			     has_color ? &color : NULL,
			     has_fcolor ? &fcolor : NULL, chcat, icon_opt->answer,
			     size, sizecolumn_opt->answer, rotcolumn_opt->answer,
			     (int)id_flag->answer, table_acolors_flag->answer,
			     cats_acolors_flag->answer, rgbcol_opt->answer,
			     default_width, wcolumn_opt->answer, width_scale,
			     zcol_flag->answer, zcol_opt->answer);
		if (wcolumn_opt->answer)
		    D_line_width(default_width);
	    }
	}

	if (has_color) {
	    R_RGB_color(color.r, color.g, color.b);
	    if (display & DISP_DIR)
                stat = dir(&Map, type, Clist, chcat, size);
	}

	/* reset line width: Do we need to get line width from display
	 * driver (not implemented)?  It will help restore previous line
	 * width (not just 0) determined by another module (e.g.,
	 * d.linewidth). */
	if (!wcolumn_opt->answer)
	    R_line_width(0);

	if (display & DISP_CAT)
	    stat = label(&Map, type, Clist, &lattr, chcat);

	if (display & DISP_ATTR)
	    stat =
		attr(&Map, type, attrcol_opt->answer, Clist, &lattr, chcat);

	if (display & DISP_ZCOOR)
	    stat = zcoor(&Map, type, &lattr);

	if (display & DISP_TOPO) {
	    if (level >= 2)
		stat = topo(&Map, type, &lattr);
	    else
		G_warning(_("Unable to display topology, not available"));
	}
    }

    if (!x_flag->answer) {
	D_add_to_list(G_recreate_command());

	D_set_dig_name(G_fully_qualified_name(map_name, mapset));
	D_add_to_dig_list(G_fully_qualified_name(map_name, mapset));
    }

    R_close_driver();

    if (verbose)
	G_done_msg(" ");

    Vect_close(&Map);
    Vect_destroy_cat_list(Clist);

    exit(stat);
}