Пример #1
0
/*!
   \brief Get list of nodes from varray

   Returns the list of all nodes on features selected by varray.
   nodes_to_features conains the index of a feature adjecent to each
   node or -1 if no such feature specified by varray
   exists. Nodes_to_features might be NULL, in which case it is left
   unitialised.

   \param map pointer to Map_info structure
   \param varray pointer to varray structure
   \param[out] nodes list of node ids
   \param node_to_features ?
 */
void NetA_varray_to_nodes(struct Map_info *map, struct varray *varray,
			  struct ilist *nodes, int *nodes_to_features)
{
    int nlines, nnodes, i;

    nlines = Vect_get_num_lines(map);
    nnodes = Vect_get_num_nodes(map);
    if (nodes_to_features)
	for (i = 1; i <= nnodes; i++)
	    nodes_to_features[i] = -1;

    for (i = 1; i <= nlines; i++)
	if (varray->c[i]) {
	    int type = Vect_read_line(map, NULL, NULL, i);

	    if (type == GV_POINT) {
		int node;

		Vect_get_line_nodes(map, i, &node, NULL);
		Vect_list_append(nodes, node);
		if (nodes_to_features)
		    nodes_to_features[node] = i;
	    }
	    else {
		int node1, node2;

		Vect_get_line_nodes(map, i, &node1, &node2);
		Vect_list_append(nodes, node1);
		Vect_list_append(nodes, node2);
		if (nodes_to_features)
		    nodes_to_features[node1] = nodes_to_features[node2] = i;
	    }
	}
}
Пример #2
0
/*!
   \brief Get node cost

   For each node in the map, finds the category of the point on it (if
   there is any) and stores the value associated with this category in
   the array node_costs. If there is no point with a category,
   node_costs=0.

   node_costs are multiplied by 1000000 and truncated to integers (as
   is done in Vect_net_build_graph)

   \param In pointer to Map_info structure
   \param layer layer number
   \param column name of column
   \param[out] node_costs list of node costs

   \returns 1 on success
   \return 0 on failure
 */
int NetA_get_node_costs(struct Map_info *In, int layer, char *column,
			int *node_costs)
{
    int i, nlines, nnodes;
    dbCatValArray vals;
    struct line_cats *Cats;
    struct line_pnts *Points;

    dbDriver *driver;
    struct field_info *Fi;

    Fi = Vect_get_field(In, layer);
    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);

    nlines = Vect_get_num_lines(In);
    nnodes = Vect_get_num_nodes(In);
    Cats = Vect_new_cats_struct();
    Points = Vect_new_line_struct();
    for (i = 1; i <= nnodes; i++)
	node_costs[i] = 0;

    db_CatValArray_init(&vals);

    if (db_select_CatValArray(driver, Fi->table, Fi->key, column, NULL, &vals)
	== -1)
	return 0;
    for (i = 1; i <= nlines; i++) {
	int type = Vect_read_line(In, Points, Cats, i);

	if (type == GV_POINT) {
	    int node, cat;
	    double value;

	    if (!Vect_cat_get(Cats, layer, &cat))
		continue;
	    Vect_get_line_nodes(In, i, &node, NULL);
	    if (db_CatValArray_get_value_double(&vals, cat, &value) == DB_OK)
		node_costs[node] = value * 1000000.0;
	}
    }

    Vect_destroy_cats_struct(Cats);
    db_CatValArray_free(&vals);
    db_close_database_shutdown_driver(driver);
    return 1;
}
Пример #3
0
bool QgsGrassFeatureIterator::fetchFeature( QgsFeature& feature )
{
  if ( mClosed )
    return false;

  feature.setValid( false );
  int cat = -1, type = -1, id = -1;
  QgsFeatureId featureId = -1;

  QgsDebugMsgLevel( "entered.", 3 );

  /* TODO: handle editing
  if ( P->isEdited() || P->isFrozen() || !P->mValid )
  {
    close();
    return false;
  }
  */

  // TODO: is this necessary? the same is checked below
  if ( !QgsGrassProvider::isTopoType( mSource->mLayerType )  && ( mSource->mCidxFieldIndex < 0 || mNextCidx >= mSource->mCidxFieldNumCats ) )
  {
    close();
    return false; // No features, no features in this layer
  }

  bool filterById = mRequest.filterType() == QgsFeatureRequest::FilterFid;

  // Get next line/area id
  int found = 0;
  while ( true )
  {
    QgsDebugMsgLevel( QString( "mNextTopoId = %1" ).arg( mNextTopoId ), 3 );
    if ( mSource->mLayerType == QgsGrassProvider::TOPO_POINT || mSource->mLayerType == QgsGrassProvider::TOPO_LINE )
    {
      if ( mNextTopoId > Vect_get_num_lines( mSource->mMap ) ) break;
      id = mNextTopoId;
      type = Vect_read_line( mSource->mMap, 0, 0, mNextTopoId++ );
      if ( !( type & mSource->mGrassType ) ) continue;
      featureId = id;
    }
    else if ( mSource->mLayerType == QgsGrassProvider::TOPO_NODE )
    {
      if ( mNextTopoId > Vect_get_num_nodes( mSource->mMap ) ) break;
      id = mNextTopoId;
      type = 0;
      mNextTopoId++;
      featureId = id;
    }
    else
    {
      if ( mNextCidx >= mSource->mCidxFieldNumCats ) break;

      Vect_cidx_get_cat_by_index( mSource->mMap, mSource->mCidxFieldIndex, mNextCidx++, &cat, &type, &id );
      // Warning: selection array is only of type line/area of current layer -> check type first
      if ( !( type & mSource->mGrassType ) )
        continue;

      // The 'id' is a unique id of a GRASS geometry object (point, line, area)
      // but it cannot be used as QgsFeatureId because one geometry object may
      // represent more features because it may have more categories.
      featureId = makeFeatureId( id, cat );
    }

    if ( filterById && featureId != mRequest.filterFid() )
      continue;

    // it is correct to use id with mSelection because mSelection is only used
    // for geometry selection
    if ( !mSelection[id] )
      continue;

    found = 1;
    break;
  }
  if ( !found )
  {
    close();
    return false; // No more features
  }
  QgsDebugMsgLevel( QString( "cat = %1 type = %2 id = %3 fatureId = %4" ).arg( cat ).arg( type ).arg( id ).arg( featureId ), 3 );

  feature.setFeatureId( featureId );
  feature.initAttributes( mSource->mFields.count() );
  feature.setFields( &mSource->mFields ); // allow name-based attribute lookups

  if ( mRequest.flags() & QgsFeatureRequest::NoGeometry )
    feature.setGeometry( 0 );
  else
    setFeatureGeometry( feature, id, type );

  if ( ! QgsGrassProvider::isTopoType( mSource->mLayerType ) )
  {
    if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes )
      setFeatureAttributes( cat, &feature, mRequest.subsetOfAttributes() );
    else
      setFeatureAttributes( cat, &feature );
  }
  else
  {
    feature.setAttribute( 0, id );
#if GRASS_VERSION_MAJOR < 7
    if ( mSource->mLayerType == QgsGrassProvider::TOPO_POINT || mSource->mLayerType == QgsGrassProvider::TOPO_LINE )
#else
    /* No more topo points in GRASS 7 */
    if ( mSource->mLayerType == QgsGrassProvider::TOPO_LINE )
#endif
    {
      feature.setAttribute( 1, QgsGrassProvider::primitiveTypeName( type ) );

      int node1, node2;
      Vect_get_line_nodes( mSource->mMap, id, &node1, &node2 );
      feature.setAttribute( 2, node1 );
      if ( mSource->mLayerType == QgsGrassProvider::TOPO_LINE )
      {
        feature.setAttribute( 3, node2 );
      }
    }

    if ( mSource->mLayerType == QgsGrassProvider::TOPO_LINE )
    {
      if ( type == GV_BOUNDARY )
      {
        int left, right;
        Vect_get_line_areas( mSource->mMap, id, &left, &right );
        feature.setAttribute( 4, left );
        feature.setAttribute( 5, right );
      }
    }
    else if ( mSource->mLayerType == QgsGrassProvider::TOPO_NODE )
    {
      QString lines;
      int nlines = Vect_get_node_n_lines( mSource->mMap, id );
      for ( int i = 0; i < nlines; i++ )
      {
        int line = Vect_get_node_line( mSource->mMap, id, i );
        if ( i > 0 ) lines += ",";
        lines += QString::number( line );
      }
      feature.setAttribute( 1, lines );
    }
  }

  feature.setValid( true );

  return true;
}
Пример #4
0
int main(int argc, char *argv[])
{
    struct Map_info In, Out;
    static struct line_pnts *Points;
    struct line_cats *Cats;
    struct GModule *module;	/* GRASS module for parsing arguments */
    struct Option *map_in, *map_out;
    struct Option *method_opt, *afield_opt, *nfield_opt, *abcol,
                  *afcol, *ncol;
    struct Flag *add_f;
    int with_z;
    int afield, nfield, mask_type;
    dglGraph_s *graph;
    int *component, nnodes, type, i, nlines, components, max_cat;
    char buf[2000], *covered;
    char *desc;

    /* Attribute table */
    dbString sql;
    dbDriver *driver;
    struct field_info *Fi;

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

    /* initialize module */
    module = G_define_module();
    G_add_keyword(_("vector"));
    G_add_keyword(_("network"));
    G_add_keyword(_("components"));
    module->description =
	_("Computes strongly and weakly connected components in the network.");

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

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

    nfield_opt = G_define_standard_option(G_OPT_V_FIELD);
    nfield_opt->key = "node_layer";
    nfield_opt->answer = "2";
    nfield_opt->label = _("Node layer");
    nfield_opt->guisection = _("Cost");

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

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

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

    map_out = G_define_standard_option(G_OPT_V_OUTPUT);

    method_opt = G_define_option();
    method_opt->key = "method";
    method_opt->type = TYPE_STRING;
    method_opt->required = YES;
    method_opt->multiple = NO;
    method_opt->options = "weak,strong";
    desc = NULL;
    G_asprintf(&desc,
	       "weak;%s;strong;%s",
	       _("Weakly connected components"),
	       _("Strongly connected components"));
    method_opt->descriptions = desc;
    method_opt->description = _("Type of components");

    add_f = G_define_flag();
    add_f->key = 'a';
    add_f->description = _("Add points on nodes");

    /* options and flags parser */
    if (G_parser(argc, argv))
	exit(EXIT_FAILURE);
    /* TODO: make an option for this */
    mask_type = GV_LINE | GV_BOUNDARY;

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

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

    Vect_set_open_level(2);

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

    with_z = Vect_is_3d(&In);

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

    /* parse filter option and select appropriate lines */
    afield = Vect_get_field_number(&In, afield_opt->answer);
    nfield = Vect_get_field_number(&In, nfield_opt->answer);

    if (0 != Vect_net_build_graph(&In, mask_type, afield, nfield, afcol->answer,
                                  abcol->answer, ncol->answer, 0, 2))
        G_fatal_error(_("Unable to build graph for vector map <%s>"), Vect_get_full_name(&In));

    graph = Vect_net_get_graph(&In);
    nnodes = Vect_get_num_nodes(&In);
    component = (int *)G_calloc(nnodes + 1, sizeof(int));
    covered = (char *)G_calloc(nnodes + 1, sizeof(char));
    if (!component || !covered) {
	G_fatal_error(_("Out of memory"));
	exit(EXIT_FAILURE);
    }
    /* Create table */
    Fi = Vect_default_field_info(&Out, 1, NULL, GV_1TABLE);
    Vect_map_add_dblink(&Out, 1, NULL, Fi->table, GV_KEY_COLUMN, Fi->database,
			Fi->driver);
    db_init_string(&sql);
    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);

    sprintf(buf, "create table %s ( cat integer, comp integer)", Fi->table);

    db_set_string(&sql, buf);
    G_debug(2, "%s", db_get_string(&sql));

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

    if (db_create_index2(driver, Fi->table, GV_KEY_COLUMN) != DB_OK)
	G_warning(_("Cannot create index"));

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

    db_begin_transaction(driver);

    if (method_opt->answer[0] == 'w') {
	G_message(_("Computing weakly connected components..."));
	components = NetA_weakly_connected_components(graph, component);
    }
    else {
	G_message(_("Computing strongly connected components..."));
	components = NetA_strongly_connected_components(graph, component);
    }

    G_debug(3, "Components: %d", components);

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

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

    nlines = Vect_get_num_lines(&In);
    max_cat = 1;
    G_percent(0, nlines, 4);
    for (i = 1; i <= nlines; i++) {
	int comp, cat;

	G_percent(i, nlines, 4);
	type = Vect_read_line(&In, Points, Cats, i);
	if (!Vect_cat_get(Cats, afield, &cat))
	    continue;
	if (type == GV_LINE || type == GV_BOUNDARY) {
	    int node1, node2;

	    Vect_get_line_nodes(&In, i, &node1, &node2);
	    if (component[node1] == component[node2]) {
		comp = component[node1];
	    }
	    else {
		continue;
	    }
	}
	else if (type == GV_POINT) {
	    int node;

	    /* Vect_get_line_nodes(&In, i, &node, NULL); */
	    node = Vect_find_node(&In, Points->x[0], Points->y[0], Points->z[0], 0, 0);
	    if (!node)
		continue;
	    comp = component[node];
	    covered[node] = 1;
	}
	else
	    continue;
	
	cat = max_cat++;
	Vect_reset_cats(Cats);
	Vect_cat_set(Cats, 1, cat);
	Vect_write_line(&Out, type, Points, Cats);
	insert_new_record(driver, Fi, &sql, cat, comp);
    }

    /*add points on nodes not covered by any point in the network */
    if (add_f->answer) {
	for (i = 1; i <= nnodes; i++)
	    if (!covered[i]) {
		Vect_reset_cats(Cats);
		Vect_cat_set(Cats, 1, max_cat);
		NetA_add_point_on_node(&In, &Out, i, Cats);
		insert_new_record(driver, Fi, &sql, max_cat++, component[i]);
	    }
    }

    db_commit_transaction(driver);
    db_close_database_shutdown_driver(driver);

    Vect_close(&In);

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

    G_done_msg(_("Found %d components."), components);

    exit(EXIT_SUCCESS);
}
Пример #5
0
int report(struct Map_info *In, int afield, int nfield, int action)
{
    int i, j, k, line, ltype, nnodes;
    int cat_line, cat_node[2];
    struct line_cats *Cats, *Cats2;
    int node;
    double x, y, z;

    Cats = Vect_new_cats_struct();
    Cats2 = Vect_new_cats_struct();

    if (action == TOOL_REPORT) {
	/* For all lines find categories for points on nodes */
	for (i = 1; i <= Vect_get_num_lines(In); i++) {
	    ltype = Vect_read_line(In, NULL, Cats, i);
	    if (ltype != GV_LINE)
		continue;

	    cat_line = 0;
	    if (!Vect_cat_get(Cats, afield, &cat_line))
		G_warning(_("Line %d has no category"), i);

	    cat_node[0] = cat_node[1] = 0;
	    for (j = 0; j < 2; j++) {
		if (j == 0)
		    Vect_get_line_nodes(In, i, &node, NULL);
		else
		    Vect_get_line_nodes(In, i, NULL, &node);

		Vect_get_node_coor(In, node, &x, &y, &z);
		nnodes = 0;

		for (k = 0; k < Vect_get_node_n_lines(In, node); k++) {
		    line = abs(Vect_get_node_line(In, node, k));
		    ltype = Vect_read_line(In, NULL, Cats, line);
		    if (ltype != GV_POINT)
			continue;

		    Vect_cat_get(Cats, nfield, &(cat_node[j]));

		    nnodes++;
		}
		if (nnodes == 0)
		    G_warning(_("Point not found: %.3lf %.3lf %.3lf line category: %d"),
			      x, y, z, cat_line);
		else if (nnodes > 1)
		    G_warning(_("%d points found: %.3lf %.3lf %.3lf line category: %d"),
			      nnodes, x, y, z, cat_line);
	    }
	    fprintf(stdout, "%d %d %d\n", cat_line, cat_node[0], cat_node[1]);
	}
    }
    else {			/* node report */

	int nnodes, node;

	nnodes = Vect_get_num_nodes(In);

	for (node = 1; node <= nnodes; node++) {
	    int nelem, elem, type, i, j, k, l;

	    nelem = Vect_get_node_n_lines(In, node);

	    /* Loop through all points */
	    for (i = 0; i < nelem; i++) {
		elem = abs(Vect_get_node_line(In, node, i));
		type = Vect_read_line(In, NULL, Cats, elem);
		if (type != GV_POINT)
		    continue;

		/* Loop through all cats of point */
		for (j = 0; j < Cats->n_cats; j++) {
		    if (Cats->field[j] == nfield) {
			int count = 0;

			fprintf(stdout, "%d ", Cats->cat[j]);

			/* Loop through all lines */
			for (k = 0; k < nelem; k++) {
			    elem = abs(Vect_get_node_line(In, node, k));
			    type = Vect_read_line(In, NULL, Cats2, elem);
			    if (!(type & GV_LINES))
				continue;

			    /* Loop through all cats of line */
			    for (l = 0; l < Cats2->n_cats; l++) {
				if (Cats2->field[l] == afield) {
				    if (count > 0)
					fprintf(stdout, ",");

				    fprintf(stdout, "%d", Cats2->cat[l]);
				    count++;
				}
			    }
			}
			fprintf(stdout, "\n");
		    }
		}
	    }
	}
    }

    return 0;
}
Пример #6
0
Файл: main.c Проект: 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);
}
Пример #7
0
void print_topo(const struct Map_info *Map)
{
    int with_z;
    long nprimitives;

    nprimitives = 0;
    with_z = Vect_is_3d(Map);

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

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

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

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

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

    fprintf(stdout, "map3d=%d\n",
	    Vect_is_3d(Map) ? 1 : 0);
    fflush(stdout);
}
Пример #8
0
int display_topo(struct Map_info *Map, int type, LATTR *lattr, double dsize)
{
    int ltype, num, el;
    double msize;
    struct line_pnts *Points;
    struct line_cats *Cats;
    char text[50];
    LATTR lattr2 = *lattr;

    if (Vect_level(Map) < 2) {
	G_warning(_("Unable to display topology, not available."
		    "Please try to rebuild topology using "
		    "v.build or v.build.all."));
	return 1;
    }
    
    msize = dsize * (D_d_to_u_col(2.0) - D_d_to_u_col(1.0));	/* do it better */
    
    lattr2.xref = lattr->xref == LRIGHT ? LLEFT : LRIGHT;

    G_debug(1, "display topo:");
    Points = Vect_new_line_struct();
    Cats = Vect_new_cats_struct();

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

    Vect_rewind(Map);

    num = Vect_get_num_lines(Map);
    G_debug(1, "n_lines = %d", num);

    /* Lines */
    for (el = 1; el <= num; el++) {
	if (!Vect_line_alive(Map, el))
	    continue;
	ltype = Vect_read_line(Map, Points, Cats, el);
	G_debug(3, "ltype = %d", ltype);
	switch (ltype) {
	case -1:
	    G_fatal_error(_("Unable to read vector map"));
	case -2:		/* EOF */
	    return 0;
	}

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

	sprintf(text, "%d", el);
	show_label_line(Points, ltype, lattr, text);
    }

    num = Vect_get_num_nodes(Map);
    G_debug(1, "n_nodes = %d", num);

    /* Nodes */
    for (el = 1; el <= num; el++) {
	double X, Y;
	if (!Vect_node_alive(Map, el))
	    continue;
	Vect_get_node_coor(Map, el, &X, &Y, NULL);
	G_debug(3, "node = %d", el);
	sprintf(text, "n%d", el);

	show_label(&X, &Y, &lattr2, text);

	D_plot_icon(X, Y, G_ICON_BOX, 0, msize);
    }

    Vect_destroy_line_struct(Points);
    Vect_destroy_cats_struct(Cats);

    return 0;
}
Пример #9
0
int main(int argc, char *argv[])
{
    struct Map_info In, Out;
    static struct line_pnts *Points, *PPoints;
    struct line_cats *Cats, *TCats;
    struct ilist *slist;
    struct GModule *module;	/* GRASS module for parsing arguments */
    struct Option *map_in, *map_out;
    struct Option *catf_opt, *fieldf_opt, *wheref_opt;
    struct Option *catt_opt, *fieldt_opt, *wheret_opt, *typet_opt;
    struct Option *afield_opt, *nfield_opt, *abcol, *afcol, *ncol, *atype_opt;
    struct Flag *geo_f, *segments_f;
    int with_z, geo, segments;
    int atype, ttype;
    struct varray *varrayf, *varrayt;
    int flayer, tlayer;
    int afield, nfield;
    dglGraph_s *graph;
    struct ilist *nodest;
    int i, j, nnodes, nlines;
    int *dst, *nodes_to_features;
    int from_nr;			/* 'from' features not reachable */
    dglInt32_t **nxt;
    struct line_cats **on_path;
    char *segdir;
    char buf[2000];

    /* Attribute table */
    dbString sql;
    dbDriver *driver;
    struct field_info *Fi;

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

    /* initialize module */
    module = G_define_module();
    G_add_keyword(_("vector"));
    G_add_keyword(_("network"));
    G_add_keyword(_("shortest path"));
    module->label = _("Computes shortest distance via the network between "
		      "the given sets of features.");
    module->description =
	_("Finds the shortest paths from each 'from' point to the nearest 'to' feature "
	 "and various information about this relation are uploaded to the attribute table.");

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

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

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

    nfield_opt = G_define_standard_option(G_OPT_V_FIELD);
    nfield_opt->key = "node_layer";
    nfield_opt->answer = "2";
    nfield_opt->label = _("Node layer");
    nfield_opt->guisection = _("Cost");

    fieldf_opt = G_define_standard_option(G_OPT_V_FIELD);
    fieldf_opt->key = "from_layer";
    fieldf_opt->label = _("From layer number or name");
    fieldf_opt->guisection = _("From");

    catf_opt = G_define_standard_option(G_OPT_V_CATS);
    catf_opt->key = "from_cats";
    catf_opt->label = _("From category values");
    catf_opt->guisection = _("From");

    wheref_opt = G_define_standard_option(G_OPT_DB_WHERE);
    wheref_opt->key = "from_where";
    wheref_opt->label =
	_("From WHERE conditions of SQL statement without 'where' keyword");
    wheref_opt->guisection = _("From");

    fieldt_opt = G_define_standard_option(G_OPT_V_FIELD);
    fieldt_opt->key = "to_layer";
    fieldt_opt->description = _("To layer number or name");
    fieldt_opt->guisection = _("To");

    typet_opt = G_define_standard_option(G_OPT_V_TYPE);
    typet_opt->key = "to_type";
    typet_opt->options = "point,line,boundary";
    typet_opt->answer = "point";
    typet_opt->description = _("To feature type");
    typet_opt->guisection = _("To");

    catt_opt = G_define_standard_option(G_OPT_V_CATS);
    catt_opt->key = "to_cats";
    catt_opt->label = _("To category values");
    catt_opt->guisection = _("To");

    wheret_opt = G_define_standard_option(G_OPT_DB_WHERE);
    wheret_opt->key = "to_where";
    wheret_opt->label =
	_("To WHERE conditions of SQL statement without 'where' keyword");
    wheret_opt->guisection = _("To");

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

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

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

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

    segments_f = G_define_flag();
#if 0
    /* use this to sync with v.net.path */
    segments_f->key = 's';
    segments_f->description = _("Write output as original input segments, "
				"not each path as one line.");
#else
    segments_f->key = 'l';
    segments_f->description = _("Write each output path as one line, "
				"not as original input segments.");
#endif

    /* options and flags parser */
    if (G_parser(argc, argv))
	exit(EXIT_FAILURE);

    atype = Vect_option_to_types(atype_opt);
    ttype = Vect_option_to_types(typet_opt);

    Points = Vect_new_line_struct();
    PPoints = Vect_new_line_struct();
    Cats = Vect_new_cats_struct();
    TCats = Vect_new_cats_struct();
    slist = G_new_ilist();

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

    Vect_set_open_level(2);

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

    with_z = Vect_is_3d(&In);

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


    if (geo_f->answer) {
	geo = 1;
	if (G_projection() != PROJECTION_LL)
	    G_warning(_("The current projection is not longitude-latitude"));
    }
    else
	geo = 0;

#if 0
    /* use this to sync with v.net.path */
    segments = segments_f->answer;
#else
    segments = !segments_f->answer;
#endif

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

    dst = (int *)G_calloc(nnodes + 1, sizeof(int));
    nxt = (dglInt32_t **) G_calloc(nnodes + 1, sizeof(dglInt32_t *));
    nodes_to_features = (int *)G_calloc(nnodes + 1, sizeof(int));
    on_path =
	(struct line_cats **)G_calloc(nlines + 1, sizeof(struct line_cats *));
    segdir = (char *)G_calloc(nlines + 1, sizeof(char));

    if (!dst || !nxt || !nodes_to_features || !on_path || !segdir)
	G_fatal_error(_("Out of memory"));

    for (i = 1; i <= nlines; i++) {
	on_path[i] = Vect_new_cats_struct();
	segdir[i] = 0;
    }

    /*initialise varrays and nodes list appropriatelly */
    afield = Vect_get_field_number(&In, afield_opt->answer);
    nfield = Vect_get_field_number(&In, nfield_opt->answer);

    flayer = atoi(fieldf_opt->answer);
    tlayer = atoi(fieldt_opt->answer);

    if (NetA_initialise_varray(&In, flayer, GV_POINT, wheref_opt->answer,
			   catf_opt->answer, &varrayf) <= 0) {
	G_fatal_error(_("No 'from' features selected. "
			"Please check options '%s', '%s', '%s'."),
			fieldf_opt->key, wheref_opt->key, catf_opt->key);
    }

    if (NetA_initialise_varray(&In, tlayer, ttype, wheret_opt->answer,
			   catt_opt->answer, &varrayt) <= 0) {
	G_fatal_error(_("No 'to' features selected. "
			"Please check options '%s', '%s', '%s'."),
			fieldt_opt->key, wheret_opt->key, catt_opt->key);
    }

    nodest = Vect_new_list();
    NetA_varray_to_nodes(&In, varrayt, nodest, nodes_to_features);
    
    if (nodest->n_values == 0)
	G_fatal_error(_("No 'to' features"));
    
    if (0 != Vect_net_build_graph(&In, atype, afield, nfield, afcol->answer, abcol->answer,
                                   ncol->answer, geo, 2))
        G_fatal_error(_("Unable to build graph for vector map <%s>"), Vect_get_full_name(&In));

    graph = Vect_net_get_graph(&In);

    G_message(_("Distances to 'to' features ..."));

    NetA_distance_to_points(graph, nodest, dst, nxt);

    /* Create table */
    Fi = Vect_default_field_info(&Out, 1, NULL, GV_1TABLE);
    Vect_map_add_dblink(&Out, 1, NULL, Fi->table, GV_KEY_COLUMN, Fi->database,
			Fi->driver);
    db_init_string(&sql);
    driver = db_start_driver_open_database(Fi->driver, Fi->database);
    if (driver == NULL)
	G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
		      Fi->database, Fi->driver);
    db_set_error_handler_driver(driver);

    sprintf(buf,
	    "create table %s ( cat integer, tcat integer, dist double precision)",
	    Fi->table);

    db_set_string(&sql, buf);
    G_debug(2, "%s", db_get_string(&sql));

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

    if (db_create_index2(driver, Fi->table, GV_KEY_COLUMN) != DB_OK)
	G_warning(_("Cannot create index"));

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

    db_begin_transaction(driver);

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

    G_message(_("Tracing paths from 'from' features ..."));
    from_nr = 0;
    for (i = 1; i <= nlines; i++) {
	if (varrayf->c[i]) {
	    int type = Vect_read_line(&In, Points, Cats, i);
	    int node, tcat, cat;
	    double cost;
	    dglInt32_t *vertex, vertex_id;

	    if (!Vect_cat_get(Cats, flayer, &cat))
		continue;
		
	    if (type & GV_POINTS) {
		node = Vect_find_node(&In, Points->x[0], Points->y[0], Points->z[0], 0, 0);
	    }
	    else {
		Vect_get_line_nodes(&In, i, &node, NULL);
	    }
	    if (node < 1)
		continue;
	    if (dst[node] < 0) {
		/* unreachable */
		from_nr++;
 		continue;
	    }
	    cost = dst[node] / (double)In.dgraph.cost_multip;
	    vertex = dglGetNode(graph, node);
	    vertex_id = node;
	    slist->n_values = 0;
	    while (nxt[vertex_id] != NULL) {
		int edge_id;

		edge_id = (int) dglEdgeGet_Id(graph, nxt[vertex_id]);
		if (segments) {
		    Vect_cat_set(on_path[abs(edge_id)], 1, cat);
		    if (edge_id < 0) {
			segdir[abs(edge_id)] = 1;
		    }
		}
		else
		    G_ilist_add(slist, edge_id);

		vertex = dglEdgeGet_Tail(graph, nxt[vertex_id]);
		vertex_id = dglNodeGet_Id(graph, vertex);
	    }
	    G_debug(3, "read line %d, vertex id %d", nodes_to_features[vertex_id], (int)vertex_id);
	    Vect_read_line(&In, NULL, TCats, nodes_to_features[vertex_id]);
	    if (!Vect_cat_get(TCats, tlayer, &tcat))
		continue;

	    Vect_write_line(&Out, type, Points, Cats);
	    sprintf(buf, "insert into %s values (%d, %d, %f)", Fi->table, cat,
		    tcat, cost);
	    db_set_string(&sql, buf);
	    G_debug(3, "%s", db_get_string(&sql));
	    if (db_execute_immediate(driver, &sql) != DB_OK) {
		G_fatal_error(_("Cannot insert new record: %s"),
			      db_get_string(&sql));
	    };

	    if (!segments) {
		Vect_reset_line(PPoints);
		for (j = 0; j < slist->n_values; j++) {
		    Vect_read_line(&In, Points, NULL, abs(slist->value[j]));
		    if (slist->value[j] > 0)
			Vect_append_points(PPoints, Points,
					   GV_FORWARD);
		    else
			Vect_append_points(PPoints, Points,
					   GV_BACKWARD);
		    PPoints->n_points--;
		}
		PPoints->n_points++;
		Vect_reset_cats(Cats);
		Vect_cat_set(Cats, 1, cat);
		Vect_write_line(&Out, GV_LINE, PPoints, Cats);
	    }

	}
    }

    if (segments) {
	for (i = 1; i <= nlines; i++) {
	    if (on_path[i]->n_cats > 0) {
		int type; 
		
		if (segdir[i]) {
		    type = Vect_read_line(&In, PPoints, NULL, i);
		    Vect_reset_line(Points);
		    Vect_append_points(Points, PPoints, GV_BACKWARD);
		}
		else
		    type = Vect_read_line(&In, Points, NULL, i);

		Vect_write_line(&Out, type, Points, on_path[i]);
	    }
	}
    }

    db_commit_transaction(driver);
    db_close_database_shutdown_driver(driver);

    Vect_build(&Out);

    Vect_close(&In);
    Vect_close(&Out);

    for (i = 1; i <= nlines; i++)
	Vect_destroy_cats_struct(on_path[i]);
    G_free(on_path);
    G_free(nodes_to_features);
    G_free(dst);
    G_free(nxt);
    G_free(segdir);

    if (from_nr)
	G_warning(n_("%d 'from' feature was not reachable",
                     "%d 'from' features were not reachable",
                     from_nr), from_nr);

    exit(EXIT_SUCCESS);
}
Пример #10
0
int main(int argc, char **argv)
{
    int i;
    int **cats, *ncats, nfields, *fields;
    struct Flag *line_flag;

    /* struct Flag *all_flag; */
    struct Option *in_opt, *out_opt;
    struct Flag *table_flag;
    struct GModule *module;
    struct line_pnts *Points;
    struct line_cats *Cats;
    int node, nnodes;
    COOR *coor;
    int ncoor, acoor;
    int line, nlines, type, ctype, area, nareas;
    int err_boundaries, err_centr_out, err_centr_dupl, err_nocentr;

    G_gisinit(argv[0]);

    module = G_define_module();
    G_add_keyword(_("vector"));
    G_add_keyword(_("geometry"));
    G_add_keyword(_("triangulation"));
    module->description = _("Creates a Voronoi diagram from an input vector "
			    "map containing points or centroids.");

    in_opt = G_define_standard_option(G_OPT_V_INPUT);
    out_opt = G_define_standard_option(G_OPT_V_OUTPUT);

    /*
       all_flag = G_define_flag ();
       all_flag->key = 'a';
       all_flag->description = _("Use all points (do not limit to current region)");
     */

    line_flag = G_define_flag();
    line_flag->key = 'l';
    line_flag->description =
	_("Output tessellation as a graph (lines), not areas");

    table_flag = G_define_flag();
    table_flag->key = 't';
    table_flag->description = _("Do not create attribute table");

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


    if (line_flag->answer)
	Type = GV_LINE;
    else
	Type = GV_BOUNDARY;

    All = 0;

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

    /* open files */
    Vect_set_open_level(2);
    Vect_open_old(&In, in_opt->answer, "");

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

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

    /* initialize working region */
    G_get_window(&Window);
    Vect_region_box(&Window, &Box);
    Box.T = 0.5;
    Box.B = -0.5;

    freeinit(&sfl, sizeof(struct Site));

    G_message(_("Reading sites..."));
    readsites();

    siteidx = 0;
    geominit();

    triangulate = 0;
    plot = 0;
    debug = 0;

    G_message(_("Voronoi triangulation..."));
    voronoi(triangulate, nextone);

    /* Close free ends by current region */
    Vect_build_partial(&Out, GV_BUILD_BASE);

    ncoor = 0;
    acoor = 100;
    coor = (COOR *) G_malloc(sizeof(COOR) * acoor);

    nnodes = Vect_get_num_nodes(&Out);
    for (node = 1; node <= nnodes; node++) {
	double x, y;

	if (Vect_get_node_n_lines(&Out, node) < 2) {	/* add coordinates */
	    Vect_get_node_coor(&Out, node, &x, &y, NULL);

	    if (ncoor == acoor - 5) {	/* always space for 5 region corners */
		acoor += 100;
		coor = (COOR *) G_realloc(coor, sizeof(COOR) * acoor);
	    }

	    coor[ncoor].x = x;
	    coor[ncoor].y = y;
	    ncoor++;
	}
    }

    /* Add region corners */
    coor[ncoor].x = Box.W;
    coor[ncoor].y = Box.S;
    ncoor++;
    coor[ncoor].x = Box.E;
    coor[ncoor].y = Box.S;
    ncoor++;
    coor[ncoor].x = Box.E;
    coor[ncoor].y = Box.N;
    ncoor++;
    coor[ncoor].x = Box.W;
    coor[ncoor].y = Box.N;
    ncoor++;

    /* Sort */
    qsort(coor, ncoor, sizeof(COOR), (void *)cmp);

    /* add last (first corner) */
    coor[ncoor].x = Box.W;
    coor[ncoor].y = Box.S;
    ncoor++;

    for (i = 1; i < ncoor; i++) {
	if (coor[i].x == coor[i - 1].x && coor[i].y == coor[i - 1].y)
	    continue;		/* duplicate */

	Vect_reset_line(Points);
	Vect_append_point(Points, coor[i].x, coor[i].y, 0.0);
	Vect_append_point(Points, coor[i - 1].x, coor[i - 1].y, 0.0);
	Vect_write_line(&Out, Type, Points, Cats);
    }

    G_free(coor);

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

    if (line_flag->answer)
	ctype = GV_POINT;
    else
	ctype = GV_CENTROID;

    nlines = Vect_get_num_lines(&In);

    G_message(_("Writing sites to output..."));

    for (line = 1; line <= nlines; line++) {

	G_percent(line, nlines, 2);

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

	if (!Vect_point_in_box(Points->x[0], Points->y[0], 0.0, &Box))
	    continue;

	Vect_write_line(&Out, ctype, Points, Cats);


	for (i = 0; i < Cats->n_cats; i++) {
	    int f, j;

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

    /* Copy tables */
    if (!(table_flag->answer)) {
	int ttype, ntabs = 0;
	struct field_info *IFi, *OFi;

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

	    IFi = Vect_get_dblink(&In, i);

	    f = -1;
	    for (j = 0; j < nfields; j++) {	/* find field */
		if (fields[j] == IFi->number) {
		    f = j;
		    break;
		}
	    }
	    if (f > -1) {
		if (ncats[f] > 0)
		    ntabs++;
	    }
	}

	if (ntabs > 1)
	    ttype = GV_MTABLE;
	else
	    ttype = GV_1TABLE;

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

	    if (fields[i] == 0)
		continue;

	    G_message(_("Layer %d"), fields[i]);

	    /* Make a list of categories */
	    IFi = Vect_get_field(&In, fields[i]);
	    if (!IFi) {		/* no table */
		G_message(_("No table"));
		continue;
	    }

	    OFi =
		Vect_default_field_info(&Out, IFi->number, IFi->name, ttype);

	    ret =
		db_copy_table_by_ints(IFi->driver, IFi->database, IFi->table,
				      OFi->driver,
				      Vect_subst_var(OFi->database, &Out),
				      OFi->table, IFi->key, cats[i],
				      ncats[i]);

	    if (ret == DB_FAILED) {
		G_warning(_("Cannot copy table"));
	    }
	    else {
		Vect_map_add_dblink(&Out, OFi->number, OFi->name, OFi->table,
				    IFi->key, OFi->database, OFi->driver);
	    }
	}
    }


    Vect_close(&In);

    /* cleaning part 1: count errors */
    Vect_build_partial(&Out, GV_BUILD_CENTROIDS);
    err_boundaries = err_centr_out = err_centr_dupl = err_nocentr = 0;
    nlines = Vect_get_num_lines(&Out);
    for (line = 1; line <= nlines; line++) {

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

	type = Vect_get_line_type(&Out, line);
	if (type == GV_BOUNDARY) {
	    int left, right;

	    Vect_get_line_areas(&Out, line, &left, &right);

	    if (left == 0 || right == 0) {
		G_debug(3, "line = %d left = %d right = %d", line, 
			left, right);
		err_boundaries++;
	    }
	}
	if (type == GV_CENTROID) {
	    area = Vect_get_centroid_area(&Out, line);
	    if (area == 0)
		err_centr_out++;
	    else if (area < 0)
		err_centr_dupl++;
	}
    }

    err_nocentr = 0;
    nareas = Vect_get_num_areas(&Out);
    for (area = 1; area <= nareas; area++) {
	if (!Vect_area_alive(&Out, area))
	    continue;
	line = Vect_get_area_centroid(&Out, area);
	if (line == 0)
	    err_nocentr++;
    }

    /* cleaning part 2: snap */
    if (err_nocentr || err_centr_dupl || err_centr_out) {
	int nmod;

	G_important_message(_("Output needs topological cleaning"));
	Vect_snap_lines(&Out, GV_BOUNDARY, 1e-7, NULL);
	do {
	    Vect_break_lines(&Out, GV_BOUNDARY, NULL);
	    Vect_remove_duplicates(&Out, GV_BOUNDARY, NULL);
	    nmod =
		Vect_clean_small_angles_at_nodes(&Out, GV_BOUNDARY, NULL);
	} while (nmod > 0);

	err_boundaries = 0;
	nlines = Vect_get_num_lines(&Out);
	for (line = 1; line <= nlines; line++) {

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

	    type = Vect_get_line_type(&Out, line);
	    if (type == GV_BOUNDARY) {
		int left, right;

		Vect_get_line_areas(&Out, line, &left, &right);

		if (left == 0 || right == 0) {
		    G_debug(3, "line = %d left = %d right = %d", line, 
			    left, right);
		    err_boundaries++;
		}
	    }
	}
    }
    /* cleaning part 3: remove remaining incorrect boundaries */
    if (err_boundaries) {
	G_important_message(_("Removing incorrect boundaries from output"));
	nlines = Vect_get_num_lines(&Out);
	for (line = 1; line <= nlines; line++) {

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

	    type = Vect_get_line_type(&Out, line);
	    if (type == GV_BOUNDARY) {
		int left, right;

		Vect_get_line_areas(&Out, line, &left, &right);

		/* &&, not ||, no typo */
		if (left == 0 && right == 0) {
		    G_debug(3, "line = %d left = %d right = %d", line, 
			    left, right);
		    Vect_delete_line(&Out, line);
		}
	    }
	}
    }

    /* build clean topology */
    Vect_build_partial(&Out, GV_BUILD_NONE);
    Vect_build(&Out);
    Vect_close(&Out);

    G_done_msg(" ");
    exit(EXIT_SUCCESS);
}
Пример #11
0
int main(int argc, char **argv)
{
    int i, j, k, ret;
    int nlines, type, ltype, afield, tfield, geo, cat;
    int sp, nsp, nspused, node, line;
    struct Option *map, *output, *afield_opt, *tfield_opt, *afcol, *type_opt,
	*term_opt, *nsp_opt;
    struct Flag *geo_f;
    struct GModule *module;
    struct Map_info Map, Out;
    int *testnode;		/* array all nodes: 1 - should be tested as Steiner, 
				 * 0 - no need to test (unreachable or terminal) */
    struct ilist *TList;	/* list of terminal nodes */
    struct ilist *StArcs;	/* list of arcs on Steiner tree */
    struct ilist *StNodes;	/* list of nodes on Steiner tree */
    struct boxlist *pointlist;
    double cost, tmpcost;
    struct cat_list *Clist;
    struct line_cats *Cats;
    struct line_pnts *Points;
    
    /* Initialize the GIS calls */
    G_gisinit(argv[0]);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    Vect_set_open_level(2);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    Vect_hist_command(&Out);

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

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

    Vect_build(&Out);

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

    exit(EXIT_SUCCESS);
}
Пример #12
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);
}
Пример #13
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);
}
Пример #14
0
int nodes(struct Map_info *In, struct Map_info *Out, int add_cats, int nfield)
{
    int i, node, nnodes, line, nlines, count, type, add_point;
    double x, y, z;

    struct line_pnts *Points, *Pout;
    struct line_cats *Cats;
    struct boxlist *List;
    struct bound_box box;

    int cat;

    Points = Vect_new_line_struct();
    Pout = Vect_new_line_struct();

    Cats = Vect_new_cats_struct();
    List = Vect_new_boxlist(0);

    /* Rewrite all primitives to output file */
    cat = 0;
    while ((type = Vect_read_next_line(In, Points, Cats)) >= 0) {
	if (type == GV_POINT) {
	    /* Get max cat in input */
	    int j;

	    for (j = 0; j < Cats->n_cats; j++) {
		if (Cats->field[j] == nfield && Cats->cat[j] > cat) {
		    cat = Cats->cat[j];
		}
	    }
	}
	Vect_write_line(Out, type, Points, Cats);
    }
    cat++;

    /* Go through all nodes in old map and write a new point if missing */
    nnodes = Vect_get_num_nodes(In);
    count = 0;
    for (node = 1; node <= nnodes; node++) {

	nlines = Vect_get_node_n_lines(In, node);
	add_point = 0;
	for (i = 0; i < nlines; i++) {
	    line = abs(Vect_get_node_line(In, node, i));
	    type = Vect_read_line(In, NULL, NULL, line);
	    if (type & GV_LINES) {
		add_point = 1;
		break;
	    }
	}

	if (add_point) {
	    Vect_get_node_coor(In, node, &x, &y, &z);
	    box.E = box.W = x;
	    box.N = box.S = y;
	    box.T = box.B = z;
	    Vect_select_lines_by_box(In, &box, GV_POINT, List);
	    add_point = List->n_values == 0;
	}

	if (add_point) {	/* Write new point */
	    Vect_reset_line(Pout);
	    Vect_append_point(Pout, x, y, z);
	    Vect_reset_cats(Cats);
	    if (add_cats) {
		Vect_cat_set(Cats, nfield, cat++);
	    }
	    Vect_write_line(Out, GV_POINT, Pout, Cats);
	    count++;
	}
    }

    Vect_destroy_line_struct(Points);
    Vect_destroy_line_struct(Pout);
    Vect_destroy_cats_struct(Cats);
    Vect_destroy_boxlist(List);

    return count;
}