Ejemplo n.º 1
0
/*!
   \brief Check if categories match with category constraints.

   \param Cats line_cats structure
   \param layer layer number
   \param list cat_list structure

   \return 0 no match, categories are outside constraints
   \return 1 match, categories are inside constraints
 */
int Vect_cats_in_constraint(struct line_cats *Cats, int layer,
			      struct cat_list *list)
{
    int i;

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

    if (list) {
	for (i = 0; i < Cats->n_cats; i++) {
	    if (Cats->field[i] == layer &&
		Vect_cat_in_cat_list(Cats->cat[i], list)) {
		return 1;
	    }
	}
	return 0;
    }

    for (i = 0; i < Cats->n_cats; i++) {
	if (Cats->field[i] == layer)
	    return 1;
    }
	
    return 0;
}
Ejemplo n.º 2
0
/* check category */
int get_cat(const struct line_cats *Cats, const struct cat_list *Clist,
	      const int *cats, int ncats, int field, int *cat)
{
    int i;
    
    *cat = -1;
    
    if (field < 1)
	return TRUE;
    
    if (Clist && Clist->field == field) {
	for (i = 0; i < Cats->n_cats; i++) {
	    if (Cats->field[i] == field &&
		Vect_cat_in_cat_list(Cats->cat[i], Clist)) {
		*cat = Cats->cat[i];
		return TRUE;
	    }
	}
	return FALSE;
    }
    if (cats) {
	int *found;

	for (i = 0; i < Cats->n_cats; i++) {
	    if (Cats->field[i] == field) {
		found = (int *)bsearch((void *) &(Cats->cat[i]), cats, 
		                       ncats, sizeof(int), srch);
		if (found) {
		    /* found */
		    *cat = *found;
		    return TRUE;
		}
	    }
	}
	return FALSE;
    }
    if (!Clist && !cats && field > 0) {
	Vect_cat_get(Cats, field, cat);
	if (*cat > -1)
	    return TRUE;
    }
    
    return FALSE;
}
Ejemplo n.º 3
0
int display_attr(struct Map_info *Map, int type, char *attrcol,
		 struct cat_list *Clist, LATTR *lattr, int chcat)
{
    int i, ltype, more;
    struct line_pnts *Points;
    struct line_cats *Cats;
    int cat;
    char buf[2000];
    struct field_info *fi;
    dbDriver *driver;
    dbString stmt, valstr, text;
    dbCursor cursor;
    dbTable *table;
    dbColumn *column;

    G_debug(2, "attr()");

    if (attrcol == NULL || *attrcol == '\0') {
	G_fatal_error(_("attrcol not specified, cannot display attributes"));
    }

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

    fi = Vect_get_field(Map, lattr->field);
    if (fi == NULL)
	return 1;

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

    Vect_rewind(Map);
    while (1) {
	ltype = Vect_read_next_line(Map, Points, Cats);
	if (ltype == -1)
	    G_fatal_error(_("Unable to read vector map"));
	else if (ltype == -2)		/* EOF */
	    break;

	if (!(type & ltype) && !((type & GV_AREA) && (ltype & GV_CENTROID)))
	    continue;		/* used for both lines and labels */

	D_RGB_color(lattr->color.R, lattr->color.G, lattr->color.B);
	D_text_size(lattr->size, lattr->size);
	if (lattr->font)
	    D_font(lattr->font);
	if (lattr->enc)
	    D_encoding(lattr->enc);

	if (chcat) {
	    int found = 0;

	    for (i = 0; i < Cats->n_cats; i++) {
		if (Cats->field[i] == Clist->field &&
		    Vect_cat_in_cat_list(Cats->cat[i], Clist)) {
		    found = 1;
		    break;
		}
	    }
	    if (!found)
		continue;
	}
	else if (Clist->field > 0) {
	    int found = 0;

	    for (i = 0; i < Cats->n_cats; i++) {
		if (Cats->field[i] == Clist->field) {
		    found = 1;
		    break;
		}
	    }
	    /* lines with no category will be displayed */
	    if (Cats->n_cats > 0 && !found)
		continue;
	}

	if (Vect_cat_get(Cats, lattr->field, &cat)) {
	    int ncats = 0;

	    /* Read attribute from db */
	    db_free_string(&text);
	    for (i = 0; i < Cats->n_cats; i++) {
		int nrows;

		if (Cats->field[i] != lattr->field)
		    continue;
		db_init_string(&stmt);
		sprintf(buf, "select %s from %s where %s = %d", attrcol,
			fi->table, fi->key, Cats->cat[i]);
		G_debug(2, "SQL: %s", buf);
		db_append_string(&stmt, buf);

		if (db_open_select_cursor
		    (driver, &stmt, &cursor, DB_SEQUENTIAL) != DB_OK)
		    G_fatal_error(_("Unable to open select cursor: '%s'"),
				  db_get_string(&stmt));

		nrows = db_get_num_rows(&cursor);

		if (ncats > 0)
		    db_append_string(&text, "/");

		if (nrows > 0) {
		    table = db_get_cursor_table(&cursor);
		    column = db_get_table_column(table, 0);	/* first column */

		    if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK)
			continue;
		    db_convert_column_value_to_string(column, &valstr);

		    db_append_string(&text, db_get_string(&valstr));
		}
		else {
		    G_warning(_("No attribute found for cat %d: %s"), cat,
			      db_get_string(&stmt));
		}

		db_close_cursor(&cursor);
		ncats++;
	    }

	    show_label_line(Points, ltype, lattr, db_get_string(&text));
	}
    }

    db_close_database_shutdown_driver(driver);
    Vect_destroy_line_struct(Points);
    Vect_destroy_cats_struct(Cats);

    return 0;
}
Ejemplo n.º 4
0
int process_line(int ltype, const struct line_pnts *Points,
		 const struct line_cats *Cats, LATTR *lattr,
		 int chcat, const struct cat_list *Clist)
{
    int i, cat, len;
    char *text = NULL, buf[100];
    
    D_RGB_color(lattr->color.R, lattr->color.G, lattr->color.B);
    D_text_size(lattr->size, lattr->size);
    if (lattr->font)
	D_font(lattr->font);
    if (lattr->enc)
	D_encoding(lattr->enc);
    
    if (chcat) {
	int found = 0;
	
	for (i = 0; i < Cats->n_cats; i++) {
	    if (Cats->field[i] == Clist->field &&
		Vect_cat_in_cat_list(Cats->cat[i], Clist)) {
		found = 1;
		break;
	    }
	}
	if (!found)
	    return 0;
    }
    else if (Clist->field > 0) {
	int found = 0;
	
	for (i = 0; i < Cats->n_cats; i++) {
	    if (Cats->field[i] == Clist->field) {
		found = 1;
		break;
	    }
	}
	/* lines with no category will be displayed */
	if (Cats->n_cats > 0 && !found)
	    return 0;
    }
    
    if (Vect_cat_get(Cats, lattr->field, &cat)) {
	for (i = 0; i < Cats->n_cats; i++) {
	    G_debug(3, "cat lab: field = %d, cat = %d", Cats->field[i],
		    Cats->cat[i]);
	    if (Cats->field[i] == lattr->field) {	/* all cats of given lfield */
		if (!text) {
		    sprintf(buf, "%d", Cats->cat[i]);
		    text = G_calloc(strlen(buf), sizeof(char));
		    text[0] = '\0';
		    strcpy(text, buf);
		}
		else {
		    sprintf(buf, "/%d", Cats->cat[i]);
		    len = strlen(text) + strlen(buf) + 1;
		    text = G_realloc(text, len * sizeof(char));
		    strcat(text, buf);
		}
	    }
	}
	show_label_line(Points, ltype, lattr, text);
    }
    
    if (text)
	G_free(text);

    return 1;
}
Ejemplo n.º 5
0
/* *************************************************************** */
int plot1(struct Map_info *Map, int type, int area, struct cat_list *Clist,
	  const struct color_rgb *color, const struct color_rgb *fcolor,
	  int chcat, SYMBOL * Symb, int size, int id_flag,
	  int table_colors_flag, int cats_color_flag, char *rgb_column,
	  int default_width, char *width_column, double width_scale)
{
    int i, ltype, nlines = 0, line, cat = -1;
    double *x, *y;
    struct line_pnts *Points, *PPoints;
    struct line_cats *Cats;
    double msize;
    int x0, y0;

    struct field_info *fi = NULL;
    dbDriver *driver = NULL;
    dbCatValArray cvarr_rgb, cvarr_width;
    dbCatVal *cv_rgb = NULL, *cv_width = NULL;
    int nrec_rgb = 0, nrec_width = 0;

    int open_db;
    int custom_rgb = FALSE;
    char colorstring[12];	/* RRR:GGG:BBB */
    int red, grn, blu;
    RGBA_Color *line_color, *fill_color, *primary_color;
    unsigned char which;
    int width;

    line_color = G_malloc(sizeof(RGBA_Color));
    fill_color = G_malloc(sizeof(RGBA_Color));
    primary_color = G_malloc(sizeof(RGBA_Color));

    primary_color->a = RGBA_COLOR_OPAQUE;

    /* change function prototype to pass RGBA_Color instead of color_rgb? */
    if (color) {
	line_color->r = color->r;
	line_color->g = color->g;
	line_color->b = color->b;
	line_color->a = RGBA_COLOR_OPAQUE;
    }
    else
	line_color->a = RGBA_COLOR_NONE;

    if (fcolor) {
	fill_color->r = fcolor->r;
	fill_color->g = fcolor->g;
	fill_color->b = fcolor->b;
	fill_color->a = RGBA_COLOR_OPAQUE;
    }
    else
	fill_color->a = RGBA_COLOR_NONE;


    msize = size * (D_d_to_u_col(2.0) - D_d_to_u_col(1.0));	/* do it better */

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

    open_db = table_colors_flag || width_column;

    if (open_db) {
	fi = Vect_get_field(Map, (Clist->field > 0 ? Clist->field : 1));
	if (fi == NULL) {
	    G_fatal_error(_("Database connection not defined for layer %d"),
			  (Clist->field > 0 ? Clist->field : 1));
	}

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

    if (table_colors_flag) {
	/* for reading RRR:GGG:BBB color strings from table */

	if (rgb_column == NULL || *rgb_column == '\0')
	    G_fatal_error(_("Color definition column not specified"));

	db_CatValArray_init(&cvarr_rgb);

	nrec_rgb = db_select_CatValArray(driver, fi->table, fi->key,
					 rgb_column, NULL, &cvarr_rgb);

	G_debug(3, "nrec_rgb (%s) = %d", rgb_column, nrec_rgb);

	if (cvarr_rgb.ctype != DB_C_TYPE_STRING)
	    G_fatal_error(_("Color definition column (%s) not a string. "
			    "Column must be of form RRR:GGG:BBB where RGB values range 0-255."),
			  rgb_column);

	if (nrec_rgb < 0)
	    G_fatal_error(_("Cannot select data (%s) from table"),
			  rgb_column);

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

	for (i = 0; i < cvarr_rgb.n_values; i++) {
	    G_debug(4, "cat = %d  %s = %s", cvarr_rgb.value[i].cat,
		    rgb_column, db_get_string(cvarr_rgb.value[i].val.s));
	}
    }

    if (width_column) {
	if (*width_column == '\0')
	    G_fatal_error(_("Line width column not specified."));

	db_CatValArray_init(&cvarr_width);

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

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

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

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

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

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

    if (open_db)
	db_close_database_shutdown_driver(driver);

    Vect_rewind(Map);

    /* Is it necessary to reset line/label color in each loop ? */

    if (color && !table_colors_flag && !cats_color_flag)
	D_RGB_color(color->r, color->g, color->b);

    if (Vect_level(Map) >= 2)
	nlines = Vect_get_num_lines(Map);

    line = 0;
    while (1) {
	if (Vect_level(Map) >= 2) {
	    line++;
	    if (line > nlines)
		return 0;
	    if (!Vect_line_alive(Map, line))
		continue;
	    ltype = Vect_read_line(Map, Points, Cats, line);
	}
	else {
	    ltype = Vect_read_next_line(Map, Points, Cats);
	    switch (ltype) {
	    case -1:
		fprintf(stderr, _("\nERROR: vector map - can't read\n"));
		return -1;
	    case -2:		/* EOF */
		return 0;
	    }
	}

	if (!(type & ltype))
	    continue;

	if (chcat) {
	    int found = 0;

	    if (id_flag) {	/* use line id */
		if (!(Vect_cat_in_cat_list(line, Clist)))
		    continue;
	    }
	    else {
		for (i = 0; i < Cats->n_cats; i++) {
		    if (Cats->field[i] == Clist->field &&
			Vect_cat_in_cat_list(Cats->cat[i], Clist)) {
			found = 1;
			break;
		    }
		}
		if (!found)
		    continue;
	    }
	}
	else if (Clist->field > 0) {
	    int found = 0;

	    for (i = 0; i < Cats->n_cats; i++) {
		if (Cats->field[i] == Clist->field) {
		    found = 1;
		    break;
		}
	    }
	    /* lines with no category will be displayed */
	    if (Cats->n_cats > 0 && !found)
		continue;
	}


	if (table_colors_flag) {

	    /* only first category */
	    cat = Vect_get_line_cat(Map, line,
				    (Clist->field > 0 ? Clist->field :
				     (Cats->n_cats >
				      0 ? Cats->field[0] : 1)));

	    if (cat >= 0) {
		G_debug(3, "display element %d, cat %d", line, cat);

		/* Read RGB colors from db for current area # */
		if (db_CatValArray_get_value(&cvarr_rgb, cat, &cv_rgb) !=
		    DB_OK) {
		    custom_rgb = FALSE;
		}
		else {
		    sprintf(colorstring, "%s", db_get_string(cv_rgb->val.s));

		    if (*colorstring != '\0') {
			G_debug(3, "element %d: colorstring: %s", line,
				colorstring);

			if (G_str_to_color(colorstring, &red, &grn, &blu) ==
			    1) {
			    custom_rgb = TRUE;
			    G_debug(3, "element:%d  cat %d r:%d g:%d b:%d",
				    line, cat, red, grn, blu);
			}
			else {
			    custom_rgb = FALSE;
			    G_warning(_("Error in color definition column (%s), element %d "
				       "with cat %d: colorstring [%s]"),
				      rgb_column, line, cat, colorstring);
			}
		    }
		    else {
			custom_rgb = FALSE;
			G_warning(_("Error in color definition column (%s), element %d with cat %d"),
				  rgb_column, line, cat);
		    }
		}
	    }			/* end if cat */
	    else {
		custom_rgb = FALSE;
	    }
	}			/* end if table_colors_flag */


	/* random colors */
	if (cats_color_flag) {
	    custom_rgb = FALSE;
	    if (Clist->field > 0) {
		cat = Vect_get_line_cat(Map, line, Clist->field);
		if (cat >= 0) {
		    G_debug(3, "display element %d, cat %d", line, cat);
		    /* fetch color number from category */
		    which = (cat % palette_ncolors);
		    G_debug(3, "cat:%d which color:%d r:%d g:%d b:%d", cat,
			    which, palette[which].R, palette[which].G,
			    palette[which].B);

		    custom_rgb = TRUE;
		    red = palette[which].R;
		    grn = palette[which].G;
		    blu = palette[which].B;
		}
	    }
	    else if (Cats->n_cats > 0) {
		/* fetch color number from layer */
		which = (Cats->field[0] % palette_ncolors);
		G_debug(3, "layer:%d which color:%d r:%d g:%d b:%d",
			Cats->field[0], which, palette[which].R,
			palette[which].G, palette[which].B);

		custom_rgb = TRUE;
		red = palette[which].R;
		grn = palette[which].G;
		blu = palette[which].B;
	    }
	}


	if (nrec_width) {

	    /* only first category */
	    cat = Vect_get_line_cat(Map, line,
				    (Clist->field > 0 ? Clist->field :
				     (Cats->n_cats >
				      0 ? Cats->field[0] : 1)));

	    if (cat >= 0) {
		G_debug(3, "display element %d, cat %d", line, cat);

		/* Read line width from db for current area # */

		if (db_CatValArray_get_value(&cvarr_width, cat, &cv_width) !=
		    DB_OK) {
		    width = default_width;
		}
		else {
		    width =
			width_scale * (cvarr_width.ctype ==
				       DB_C_TYPE_INT ? cv_width->val.
				       i : (int)cv_width->val.d);
		    if (width < 0) {
			G_warning(_("Error in line width column (%s), element %d "
				   "with cat %d: line width [%d]"),
				  width_column, line, cat, width);
			width = default_width;
		    }
		}
	    }			/* end if cat */
	    else {
		width = default_width;
	    }

	    D_line_width(width);
	}			/* end if nrec_width */


	/* enough of the prep work, lets start plotting stuff */
	x = Points->x;
	y = Points->y;

	if ((ltype & GV_POINTS) && Symb != NULL) {
	    if (!(color || fcolor || custom_rgb))
		continue;

	    x0 = D_u_to_d_col(x[0]);
	    y0 = D_u_to_d_row(y[0]);

	    /* skip if the point is outside of the display window */
	    /*      xy<0 tests make it go ever-so-slightly faster */
	    if (x0 < 0 || y0 < 0 ||
		x0 > D_get_d_east() || x0 < D_get_d_west() ||
		y0 > D_get_d_south() || y0 < D_get_d_north())
		continue;

	    /* use random or RGB column color if given, otherwise reset */
	    /* centroids always use default color to stand out from underlying area */
	    if (custom_rgb && (ltype != GV_CENTROID)) {
		primary_color->r = (unsigned char)red;
		primary_color->g = (unsigned char)grn;
		primary_color->b = (unsigned char)blu;
		D_symbol2(Symb, x0, y0, primary_color, line_color);
	    }
	    else
		D_symbol(Symb, x0, y0, line_color, fill_color);


	}
	else if (color || custom_rgb) {
	    if (!table_colors_flag && !cats_color_flag)
		D_RGB_color(color->r, color->g, color->b);
	    else {
		if (custom_rgb)
		    D_RGB_color((unsigned char)red, (unsigned char)grn,
				(unsigned char)blu);
		else
		    D_RGB_color(color->r, color->g, color->b);
	    }

	    /* Plot the lines */
	    if (Points->n_points == 1)	/* line with one coor */
		D_polydots_abs(x, y, Points->n_points);
	    else		/*use different user defined render methods */
		D_polyline_abs(x, y, Points->n_points);
	}
    }

    Vect_destroy_line_struct(Points);
    Vect_destroy_cats_struct(Cats);

    return 0;			/* not reached */
}
Ejemplo n.º 6
0
Archivo: main.c Proyecto: 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);
}
Ejemplo n.º 7
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);
}
Ejemplo n.º 8
0
/*!
   \brief Set values in 'varray' to 'value' from category list

   If category of object of given type is in <em>clist</em> (category
   list).  <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 clist list of 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_list(const struct Map_info *Map, int field,
			      struct cat_list *clist, int type, int value,
			      struct varray * varray)
{
    int i, n, centr, cat;
    int ni = 0;			/* number of items set */
    int ltype;			/* line type */
    struct line_cats *Cats;

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

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

    Cats = Vect_new_cats_struct();

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

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

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

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

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

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

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

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

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

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

    }

    Vect_destroy_cats_struct(Cats);

    return ni;
}
Ejemplo n.º 9
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);
}
Ejemplo n.º 10
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);
}
Ejemplo n.º 11
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);
}
Ejemplo n.º 12
0
Archivo: area.c Proyecto: caomw/grass
int display_area(struct Map_info *Map, struct cat_list *Clist, const struct Cell_head *window,
		 const struct color_rgb *bcolor, const struct color_rgb *fcolor, int chcat,
		 int id_flag, int cats_color_flag, 
		 int default_width, double width_scale,
		 struct Colors *zcolors,
		 dbCatValArray *cvarr_rgb, struct Colors *colors,
		 dbCatValArray *cvarr_width, int nrec_width)
{
    int num, area, isle, n_isles, n_points;
    double xl, yl;
    struct line_pnts *Points, * APoints, **IPoints;
    struct line_cats *Cats;
    int n_ipoints_alloc;
    int cat, centroid;
    int red, grn, blu;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    return 0;
}
Ejemplo n.º 13
0
int draw_line(int ltype, int line,
              const struct line_pnts *Points, const struct line_cats *Cats,
              int chcat, double size, int default_width,
              const struct cat_list *Clist, SYMBOL * Symb,
              RGBA_Color * primary_color,
              int *n_points, int *n_lines, int *n_centroids,
              int *n_boundaries, int *n_faces, RGBA_Color *secondary_color)
{
    double var_size, rotation;
    int i;
    double x0, y0;
    double *x, *y;
    int found, cat;

    rotation = 0.0;
    var_size = size;
    cat = -1;

    if (!ltype)
        return 0;

    if (Points->n_points == 0)
        return 0;

    found = FALSE;
    if (chcat) {
        for (i = 0; i < Cats->n_cats; i++) {
            if (Cats->field[i] == Clist->field &&
                Vect_cat_in_cat_list(Cats->cat[i], Clist)) {
                found = TRUE;
                break;
            }
        }
        if (!found)
            return 0;
    }
    else if (Clist->field > 0) {
        for (i = 0; i < Cats->n_cats; i++) {
            if (Cats->field[i] == Clist->field) {
                found = TRUE;
                break;
            }
        }
        /* lines with no category will be displayed */
        if (Cats->n_cats > 0 && !found)
            return 0;
    }

    G_debug(3, "\tdisplay feature %d, cat %d", line, cat);


    /* enough of the prep work, lets start plotting stuff */
    x = Points->x;
    y = Points->y;

    if ((ltype & GV_POINTS)) {
        x0 = x[0];
        y0 = y[0];

        /* skip if the point is outside of the display window */
        /* xy < 0 tests make it go ever-so-slightly faster */
        if (x0 > D_get_u_east() || x0 < D_get_u_west() ||
            y0 < D_get_u_south() || y0 > D_get_u_north())
            return 0;

        D_line_width(default_width);
        D_symbol2(Symb, x0, y0, primary_color, secondary_color);
    }
    else {
        /* Plot the lines */
        D_line_width(default_width);
        D_RGB_color(primary_color->r, primary_color->g, primary_color->b);
        if (Points->n_points == 1)      /* line with one coor */
            D_polydots_abs(x, y, Points->n_points);
        else                    /* use different user defined render methods */
            D_polyline_abs(x, y, Points->n_points);
    }

    switch (ltype) {
    case GV_POINT:
        (*n_points)++;
        break;
    case GV_LINE:
        (*n_lines)++;
        break;
    case GV_CENTROID:
        (*n_centroids)++;
        break;
    case GV_BOUNDARY:
        (*n_boundaries)++;
        break;
    case GV_FACE:
        (*n_faces)++;
        break;
    default:
        break;
    }

    return 1;
}