/**************************************************************** * * MODULE: v.net.components * * AUTHOR(S): Daniel Bundala * * PURPOSE: Computes strongly and weakly connected components * * COPYRIGHT: (C) 2002-2005 by the GRASS Development Team * * This program is free software under the * GNU General Public License (>=v2). * Read the file COPYING that comes with GRASS * for details. * ****************************************************************/ #include #include #include #include #include #include #include int insert_new_record(dbDriver * driver, struct field_info *Fi, dbString * sql, int cat, int comp) { char buf[2000]; sprintf(buf, "insert into %s values (%d, %d)", Fi->table, cat, comp); db_set_string(sql, buf); G_debug(3, db_get_string(sql)); if (db_execute_immediate(driver, sql) != DB_OK) { db_close_database_shutdown_driver(driver); G_fatal_error(_("Cannot insert new record: %s"), db_get_string(sql)); return 0; }; return 1; } 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 *field_opt, *method_opt; struct Flag *add_f; int with_z; int layer, mask_type; dglGraph_s *graph; int *component, nnodes, type, i, nlines, components, j, max_cat; char buf[2000], *covered; /* 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); field_opt = G_define_standard_option(G_OPT_V_FIELD); 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"; method_opt->descriptions = _("weak;Weakly connected components;" "strong;Strongly connected components;"); 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, GV_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 */ layer = atoi(field_opt->answer); Vect_net_build_graph(&In, mask_type, 0, 0, NULL, NULL, NULL, 0, 0); graph = &(In.graph); 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, layer, NULL, GV_1TABLE); Vect_map_add_dblink(&Out, layer, NULL, Fi->table, "cat", 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, 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, "cat") != 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') components = NetA_weakly_connected_components(graph, component); else components = NetA_strongly_connected_components(graph, component); G_debug(3, "Components: %d", components); Vect_copy_head_data(&In, &Out); Vect_hist_copy(&In, &Out); Vect_hist_command(&Out); nlines = Vect_get_num_lines(&In); for (i = 1; i <= nlines; i++) { int comp, cat; type = Vect_read_line(&In, Points, Cats, i); if (!Vect_cat_get(Cats, layer, &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); comp = component[node]; covered[node] = 1; } else continue; Vect_write_line(&Out, type, Points, Cats); insert_new_record(driver, Fi, &sql, cat, comp); /* for(j=0;jn_cats;j++) * if(Cats->field[j] == layer) * insert_new_record(driver, Fi, &sql, Cats->cat[j], comp); */ }; /*add points on nodes not covered by any point in the network */ /*find the maximum cat number */ if (add_f->answer) { max_cat = 0; for (i = 1; i <= nlines; i++) { Vect_read_line(&In, NULL, Cats, i); for (j = 0; j < Cats->n_cats; j++) if (Cats->cat[j] > max_cat) max_cat = Cats->cat[j]; } max_cat++; for (i = 1; i <= nnodes; i++) if (!covered[i]) { Vect_reset_cats(Cats); Vect_cat_set(Cats, layer, 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_build(&Out); Vect_close(&In); Vect_close(&Out); exit(EXIT_SUCCESS); }