static int clipper(dglGraph_s * pgraph, dglSPClipInput_s * pIn, dglSPClipOutput_s * pOut, void *pvarg /* caller's pointer */ ) { ClipperContext_s *pclip = (ClipperContext_s *) pvarg; #if 0 dglInt32_t *pnFromXYZ = (dglInt32_t *) dglNodeGet_Attr(pgraph, pIn->pnNodeFrom); dglInt32_t *pnToXYZ = (dglInt32_t *) dglNodeGet_Attr(pgraph, pIn->pnNodeTo); printf("clipper called:\n"); printf(" from node: %ld - attributes x=%ld y=%ld z=%ld\n", dglNodeGet_Id(pgraph, pIn->pnNodeFrom), pnFromXYZ[0], pnFromXYZ[1], pnFromXYZ[2]); printf(" to node: %ld - attributes x=%ld y=%ld z=%ld\n", dglNodeGet_Id(pgraph, pIn->pnNodeTo), pnToXYZ[0], pnToXYZ[1], pnToXYZ[2]); printf(" edge : %ld\n", dglEdgeGet_Id(pgraph, pIn->pnEdge)); #endif if (pclip) { if (dglNodeGet_Id(pgraph, pIn->pnNodeTo) == pclip->node_to_discard) { /* printf( " discarder.\n" ); */ return 1; } } /* printf( " accepted.\n" ); */ return 0; }
static int clipper(dglGraph_s * pgraph, dglSPClipInput_s * pargIn, dglSPClipOutput_s * pargOut, void *pvarg) { /* caller's pointer */ dglInt32_t cost; dglInt32_t from; G_debug(3, "Net: clipper()"); from = dglNodeGet_Id(pgraph, pargIn->pnNodeFrom); G_debug(3, " Edge = %d NodeFrom = %d NodeTo = %d edge cost = %d", (int)dglEdgeGet_Id(pgraph, pargIn->pnEdge), (int)from, (int)dglNodeGet_Id(pgraph, pargIn->pnNodeTo), (int)pargOut->nEdgeCost); if (from != From_node) { /* do not clip first */ if (dglGet_NodeAttrSize(pgraph) > 0) { memcpy(&cost, dglNodeGet_Attr(pgraph, pargIn->pnNodeFrom), sizeof(cost)); if (cost == -1) { /* closed, cannot go from this node except it is 'from' node */ G_debug(3, " closed node"); return 1; } else { G_debug(3, " EdgeCost += %d (node)", (int)cost); pargOut->nEdgeCost += cost; } } } else { G_debug(3, " don't clip first node"); } return 0; }
static int _print_node(dglGraph_s * pgraph, dglInt32_t * pnode, void *pvarg) { FILE *f = (FILE *) pvarg; dglInt32_t *pedgeset; dglInt32_t *pedge; dglInt32_t *ptonode; dglInt32_t *pnattr; int iAttr, cAttr; int role; int i; dglEdgesetTraverser_s edgeaT; role = 0; if (dglNodeGet_Status(pgraph, pnode) & DGL_NS_HEAD) { role |= 1; } if (dglNodeGet_Status(pgraph, pnode) & DGL_NS_TAIL) { role |= 2; } fprintf(f, "HEAD %-8ld - %-s", dglNodeGet_Id(pgraph, pnode), (role > 2) ? "'H/T'" : (role == 2) ? "'T '" : (role == 1) ? "'H '" : "'A '"); if ((cAttr = dglGet_NodeAttrSize(pgraph)) > 0) { pnattr = dglNodeGet_Attr(pgraph, pnode); fprintf(f, " - HEAD ATTR ["); for (iAttr = 0; iAttr < cAttr; iAttr++) { if (iAttr && !(iAttr % 4)) fprintf(f, " "); fprintf(f, "%02x", ((unsigned char *)pnattr)[iAttr]); } fprintf(f, "]\n"); } else { fprintf(f, "\n"); } if (role & 1) { pedgeset = dglNodeGet_OutEdgeset(pgraph, pnode); dglEdgeset_T_Initialize(&edgeaT, pgraph, pedgeset); for (i = 0, pedge = dglEdgeset_T_First(&edgeaT); pedge; i++, pedge = dglEdgeset_T_Next(&edgeaT) ) { ptonode = dglEdgeGet_Tail(pgraph, pedge); if (ptonode) { role = 0; if (dglNodeGet_Status(pgraph, ptonode) & DGL_NS_HEAD) { role |= 1; } if (dglNodeGet_Status(pgraph, ptonode) & DGL_NS_TAIL) { role |= 2; } fprintf(f, "EDGE #%-8d: TAIL %-8ld - %-s - COST %-8ld - ID %-8ld", i, dglNodeGet_Id(pgraph, ptonode), (role > 2) ? "'H/T'" : (role == 2) ? "'T '" : (role == 1) ? "'H '" : "'A '", dglEdgeGet_Cost(pgraph, pedge), dglEdgeGet_Id(pgraph, pedge) ); if ((cAttr = dglGet_NodeAttrSize(pgraph)) > 0) { pnattr = dglNodeGet_Attr(pgraph, ptonode); fprintf(f, " - TAIL ATTR ["); for (iAttr = 0; iAttr < cAttr; iAttr++) { if (iAttr && !(iAttr % 4)) fprintf(f, " "); fprintf(f, "%02x", ((unsigned char *)pnattr)[iAttr]); } fprintf(f, "]"); } if ((cAttr = dglGet_EdgeAttrSize(pgraph)) > 0) { pnattr = dglEdgeGet_Attr(pgraph, pedge); fprintf(f, " - EDGE ATTR ["); for (iAttr = 0; iAttr < cAttr; iAttr++) { if (iAttr && !(iAttr % 4)) fprintf(f, " "); fprintf(f, "%02x", ((unsigned char *)pnattr)[iAttr]); } fprintf(f, "]\n"); } else { fprintf(f, "\n"); } } } dglEdgeset_T_Release(&edgeaT); } return 0; }
/*! \brief Get number of articulation points in the graph \param graph input graph \param[out] articulation_list list of articulation points \return number of points \return -1 on error */ int NetA_articulation_points(dglGraph_s * graph, struct ilist *articulation_list) { int nnodes; int points = 0; dglEdgesetTraverser_s *current; /*edge to be processed when the node is visited */ int *tin, *min_tin; /*time in, and smallest tin over all successors. 0 if not yet visited */ dglInt32_t **parent; /*parents of the nodes */ dglInt32_t **stack; /*stack of nodes */ dglInt32_t **current_edge; /*current edge for each node */ int *mark; /*marked articulation points */ dglNodeTraverser_s nt; dglInt32_t *current_node; int stack_size; int i, time; nnodes = dglGet_NodeCount(graph); current = (dglEdgesetTraverser_s *) G_calloc(nnodes + 1, sizeof(dglEdgesetTraverser_s)); tin = (int *)G_calloc(nnodes + 1, sizeof(int)); min_tin = (int *)G_calloc(nnodes + 1, sizeof(int)); parent = (dglInt32_t **) G_calloc(nnodes + 1, sizeof(dglInt32_t *)); stack = (dglInt32_t **) G_calloc(nnodes + 1, sizeof(dglInt32_t *)); current_edge = (dglInt32_t **) G_calloc(nnodes + 1, sizeof(dglInt32_t *)); mark = (int *)G_calloc(nnodes + 1, sizeof(int)); if (!tin || !min_tin || !parent || !stack || !current || !mark) { G_fatal_error(_("Out of memory")); return -1; } for (i = 1; i <= nnodes; i++) { dglEdgeset_T_Initialize(¤t[i], graph, dglNodeGet_OutEdgeset(graph, dglGetNode(graph, i))); current_edge[i] = dglEdgeset_T_First(¤t[i]); tin[i] = mark[i] = 0; } dglNode_T_Initialize(&nt, graph); time = 0; for (current_node = dglNode_T_First(&nt); current_node; current_node = dglNode_T_Next(&nt)) { dglInt32_t current_id = dglNodeGet_Id(graph, current_node); if (tin[current_id] == 0) { int children = 0; /*number of subtrees rooted at the root/current_node */ stack[0] = current_node; stack_size = 1; parent[current_id] = NULL; while (stack_size) { dglInt32_t *node = stack[stack_size - 1]; dglInt32_t node_id = dglNodeGet_Id(graph, node); if (tin[node_id] == 0) /*vertex visited for the first time */ min_tin[node_id] = tin[node_id] = ++time; else { /*return from the recursion */ dglInt32_t to = dglNodeGet_Id(graph, dglEdgeGet_Tail(graph, current_edge [node_id])); if (min_tin[to] >= tin[node_id]) /*no path from the subtree above the current node */ mark[node_id] = 1; /*so the current node must be an articulation point */ if (min_tin[to] < min_tin[node_id]) min_tin[node_id] = min_tin[to]; current_edge[node_id] = dglEdgeset_T_Next(¤t[node_id]); /*proceed to the next edge */ } /*try next edges */ for (; current_edge[node_id]; current_edge[node_id] = dglEdgeset_T_Next(¤t[node_id])) { dglInt32_t *to = dglEdgeGet_Tail(graph, current_edge[node_id]); if (to == parent[node_id]) continue; /*skip parent */ int to_id = dglNodeGet_Id(graph, to); if (tin[to_id]) { /*back edge, cannot be a bridge/articualtion point */ if (tin[to_id] < min_tin[node_id]) min_tin[node_id] = tin[to_id]; } else { /*forward edge */ if (node_id == current_id) children++; /*if root, increase number of children */ parent[to_id] = node; stack[stack_size++] = to; break; } } if (!current_edge[node_id]) stack_size--; /*current node completely processed */ } if (children > 1) mark[current_id] = 1; /*if the root has more than 1 subtrees rooted at it, then it is an * articulation point */ } } for (i = 1; i <= nnodes; i++) if (mark[i]) { points++; Vect_list_append(articulation_list, i); } dglNode_T_Release(&nt); for (i = 1; i <= nnodes; i++) dglEdgeset_T_Release(¤t[i]); G_free(current); G_free(tin); G_free(min_tin); G_free(parent); G_free(stack); G_free(current_edge); return points; }
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); }
/*! \brief Get number of bridges in the graph. Bridge is an array containing the indices of the bridges. \param graph input graph \param[out] bridge_list list of bridges \return number of bridges, -1 on error */ int NetA_compute_bridges(dglGraph_s * graph, struct ilist *bridge_list) { int nnodes; int bridges = 0; dglEdgesetTraverser_s *current; /*edge to be processed when the node is visited */ int *tin, *min_tin; /*time in, and smallest tin over all successors. 0 if not yet visited */ dglInt32_t *parent; /*edge from parent to the node */ dglInt32_t **stack; /*stack of nodes */ dglInt32_t **current_edge; /*current edge for each node */ dglNodeTraverser_s nt; dglInt32_t *current_node; int stack_size; int i, time; nnodes = dglGet_NodeCount(graph); current = (dglEdgesetTraverser_s *) G_calloc(nnodes + 1, sizeof(dglEdgesetTraverser_s)); tin = (int *)G_calloc(nnodes + 1, sizeof(int)); min_tin = (int *)G_calloc(nnodes + 1, sizeof(int)); parent = (dglInt32_t *) G_calloc(nnodes + 1, sizeof(dglInt32_t)); stack = (dglInt32_t **) G_calloc(nnodes + 1, sizeof(dglInt32_t *)); current_edge = (dglInt32_t **) G_calloc(nnodes + 1, sizeof(dglInt32_t *)); if (!tin || !min_tin || !parent || !stack || !current) { G_fatal_error(_("Out of memory")); return -1; } for (i = 1; i <= nnodes; i++) { dglEdgeset_T_Initialize(¤t[i], graph, dglNodeGet_OutEdgeset(graph, dglGetNode(graph, i))); current_edge[i] = dglEdgeset_T_First(¤t[i]); tin[i] = 0; } dglNode_T_Initialize(&nt, graph); time = 0; for (current_node = dglNode_T_First(&nt); current_node; current_node = dglNode_T_Next(&nt)) { dglInt32_t current_id = dglNodeGet_Id(graph, current_node); if (tin[current_id] == 0) { stack[0] = current_node; stack_size = 1; parent[current_id] = 0; while (stack_size) { dglInt32_t *node = stack[stack_size - 1]; dglInt32_t node_id = dglNodeGet_Id(graph, node); if (tin[node_id] == 0) /*vertex visited for the first time */ min_tin[node_id] = tin[node_id] = ++time; else { /*return from the recursion */ dglInt32_t to = dglNodeGet_Id(graph, dglEdgeGet_Tail(graph, current_edge [node_id])); if (min_tin[to] > tin[node_id]) { /*no path from the subtree above the current node */ Vect_list_append(bridge_list, dglEdgeGet_Id(graph, current_edge[node_id])); /*so it must be a bridge */ bridges++; } if (min_tin[to] < min_tin[node_id]) min_tin[node_id] = min_tin[to]; current_edge[node_id] = dglEdgeset_T_Next(¤t[node_id]); /*proceed to the next edge */ } for (; current_edge[node_id]; current_edge[node_id] = dglEdgeset_T_Next(¤t[node_id])) { /*try next edges */ dglInt32_t *to = dglEdgeGet_Tail(graph, current_edge[node_id]); dglInt32_t edge_id = dglEdgeGet_Id(graph, current_edge[node_id]); if (abs(edge_id) == parent[node_id]) continue; /*skip edge we used to travel to this node */ int to_id = dglNodeGet_Id(graph, to); if (tin[to_id]) { /*back edge, cannot be a bridge/articualtion point */ if (tin[to_id] < min_tin[node_id]) min_tin[node_id] = tin[to_id]; } else { /*forward edge */ parent[to_id] = abs(edge_id); stack[stack_size++] = to; break; } } if (!current_edge[node_id]) stack_size--; /*current node completely processed */ } } } dglNode_T_Release(&nt); for (i = 1; i <= nnodes; i++) dglEdgeset_T_Release(¤t[i]); G_free(current); G_free(tin); G_free(min_tin); G_free(parent); G_free(stack); G_free(current_edge); return bridges; }
/*! \brief Computes shortests paths to every node from nodes in "from". Array "dst" contains the length of the path or -1 if the node is not reachable. Prev contains edges from predecessor along the shortest path. \param graph input graph \param from list of 'from' positions \param dst list of 'to' positions \param[out] prev list of edges from predecessor along the shortest path \return 0 on success \return -1 on failure */ int NetA_distance_from_points(dglGraph_s *graph, struct ilist *from, int *dst, dglInt32_t **prev) { int i, nnodes; dglHeap_s heap; nnodes = dglGet_NodeCount(graph); dglEdgesetTraverser_s et; /* initialize costs and edge list */ for (i = 1; i <= nnodes; i++) { dst[i] = -1; prev[i] = NULL; } dglHeapInit(&heap); for (i = 0; i < from->n_values; i++) { int v = from->value[i]; if (dst[v] == 0) continue; /*ingore duplicates */ dst[v] = 0; /* make sure all from nodes are processed first */ dglHeapData_u heap_data; heap_data.ul = v; dglHeapInsertMin(&heap, 0, ' ', heap_data); } while (1) { dglInt32_t v, dist; dglHeapNode_s heap_node; dglHeapData_u heap_data; if (!dglHeapExtractMin(&heap, &heap_node)) break; v = heap_node.value.ul; dist = heap_node.key; if (dst[v] < dist) continue; dglInt32_t *edge; dglEdgeset_T_Initialize(&et, graph, dglNodeGet_OutEdgeset(graph, dglGetNode(graph, v))); for (edge = dglEdgeset_T_First(&et); edge; edge = dglEdgeset_T_Next(&et)) { dglInt32_t *to = dglEdgeGet_Tail(graph, edge); dglInt32_t to_id = dglNodeGet_Id(graph, to); dglInt32_t d = dglEdgeGet_Cost(graph, edge); if (dst[to_id] < 0 || dst[to_id] > dist + d) { dst[to_id] = dist + d; prev[to_id] = edge; heap_data.ul = to_id; dglHeapInsertMin(&heap, dist + d, ' ', heap_data); } } dglEdgeset_T_Release(&et); } dglHeapFree(&heap, NULL); return 0; }
/*! \brief Find a path (minimum number of edges) from 'from' to 'to' using only edges in 'edges'. Precisely, edge with id I is used if edges[abs(i)] == 1. List stores the indices of lines on the path. Method return number of edges or -1 if no path exist. \param graph input graph \param from 'from' position \param to 'to' position \param edges list of available edges \param[out] list list of edges \return number of edges \return -1 on failure */ int NetA_find_path(dglGraph_s * graph, int from, int to, int *edges, struct ilist *list) { dglInt32_t **prev, *queue; dglEdgesetTraverser_s et; char *vis; int begin, end, cur, nnodes; nnodes = dglGet_NodeCount(graph); prev = (dglInt32_t **) G_calloc(nnodes + 1, sizeof(dglInt32_t *)); queue = (dglInt32_t *) G_calloc(nnodes + 1, sizeof(dglInt32_t)); vis = (char *)G_calloc(nnodes + 1, sizeof(char)); if (!prev || !queue || !vis) { G_fatal_error(_("Out of memory")); return -1; } Vect_reset_list(list); begin = 0; end = 1; vis[from] = 'y'; queue[0] = from; prev[from] = NULL; while (begin != end) { dglInt32_t vertex = queue[begin++]; if (vertex == to) break; dglInt32_t *edge, *node = dglGetNode(graph, vertex); dglEdgeset_T_Initialize(&et, graph, dglNodeGet_OutEdgeset(graph, node)); for (edge = dglEdgeset_T_First(&et); edge; edge = dglEdgeset_T_Next(&et)) { dglInt32_t id = abs(dglEdgeGet_Id(graph, edge)); dglInt32_t to = dglNodeGet_Id(graph, dglEdgeGet_Tail(graph, edge)); if (edges[id] && !vis[to]) { vis[to] = 'y'; prev[to] = edge; queue[end++] = to; } } dglEdgeset_T_Release(&et); } G_free(queue); if (!vis[to]) { G_free(prev); G_free(vis); return -1; } cur = to; while (prev[cur] != NULL) { Vect_list_append(list, abs(dglEdgeGet_Id(graph, prev[cur]))); cur = dglNodeGet_Id(graph, dglEdgeGet_Head(graph, prev[cur])); } G_free(prev); G_free(vis); return list->n_values; }
/*! \brief Computes weakly connected components \param graph input graph \param[out] component array of component ids \return number of components \return -1 on failure */ int NetA_weakly_connected_components(dglGraph_s * graph, int *component) { int nnodes, i; dglInt32_t *stack; int stack_size, components; dglInt32_t *cur_node; dglNodeTraverser_s nt; int have_node_costs; dglInt32_t ncost; if (graph->Version < 2) { G_warning("Directed graph must be version 2 or 3 for NetA_weakly_connected_components()"); return -1; } components = 0; nnodes = dglGet_NodeCount(graph); stack = (dglInt32_t *) G_calloc(nnodes + 1, sizeof(dglInt32_t)); if (!stack) { G_fatal_error(_("Out of memory")); return -1; } for (i = 1; i <= nnodes; i++) component[i] = 0; ncost = 0; have_node_costs = dglGet_NodeAttrSize(graph); dglNode_T_Initialize(&nt, graph); for (cur_node = dglNode_T_First(&nt); cur_node; cur_node = dglNode_T_Next(&nt)) { dglInt32_t cur_node_id = dglNodeGet_Id(graph, cur_node); if (!component[cur_node_id]) { stack[0] = cur_node_id; stack_size = 1; component[cur_node_id] = ++components; while (stack_size) { dglInt32_t *node, *edgeset, *edge; dglEdgesetTraverser_s et; node = dglGetNode(graph, stack[--stack_size]); edgeset = dglNodeGet_OutEdgeset(graph, node); dglEdgeset_T_Initialize(&et, graph, edgeset); for (edge = dglEdgeset_T_First(&et); edge; edge = dglEdgeset_T_Next(&et)) { dglInt32_t to; to = dglNodeGet_Id(graph, dglEdgeGet_Tail(graph, edge)); if (!component[to]) { component[to] = components; /* do not go through closed nodes */ if (have_node_costs) { memcpy(&ncost, dglNodeGet_Attr(graph, dglEdgeGet_Tail(graph, edge)), sizeof(ncost)); } if (ncost >= 0) stack[stack_size++] = to; } } dglEdgeset_T_Release(&et); edgeset = dglNodeGet_InEdgeset(graph, node); dglEdgeset_T_Initialize(&et, graph, edgeset); for (edge = dglEdgeset_T_First(&et); edge; edge = dglEdgeset_T_Next(&et)) { dglInt32_t to; to = dglNodeGet_Id(graph, dglEdgeGet_Head(graph, edge)); if (!component[to]) { component[to] = components; /* do not go through closed nodes */ if (have_node_costs) { memcpy(&ncost, dglNodeGet_Attr(graph, dglEdgeGet_Tail(graph, edge)), sizeof(ncost)); } if (ncost >= 0) stack[stack_size++] = to; } } dglEdgeset_T_Release(&et); } } } dglNode_T_Release(&nt); G_free(stack); return components; }
/*! \brief Computes strongly connected components with Kosaraju's two-pass algorithm \param graph input graph \param[out] component array of component ids \return number of components \return -1 on failure */ int NetA_strongly_connected_components(dglGraph_s * graph, int *component) { int nnodes, i; dglInt32_t *stack, *order; int *processed; int stack_size, order_size, components; dglInt32_t *cur_node; dglNodeTraverser_s nt; int have_node_costs; dglInt32_t ncost; if (graph->Version < 2) { G_warning("Directed graph must be version 2 or 3 for NetA_strongly_connected_components()"); return -1; } components = 0; nnodes = dglGet_NodeCount(graph); stack = (dglInt32_t *) G_calloc(nnodes + 1, sizeof(dglInt32_t)); order = (dglInt32_t *) G_calloc(nnodes + 1, sizeof(dglInt32_t)); processed = (int *)G_calloc(nnodes + 1, sizeof(int)); if (!stack || !order || !processed) { G_fatal_error(_("Out of memory")); return -1; } for (i = 1; i <= nnodes; i++) { component[i] = 0; } ncost = 0; have_node_costs = dglGet_NodeAttrSize(graph); order_size = 0; dglNode_T_Initialize(&nt, graph); for (cur_node = dglNode_T_First(&nt); cur_node; cur_node = dglNode_T_Next(&nt)) { dglInt32_t cur_node_id = dglNodeGet_Id(graph, cur_node); if (!component[cur_node_id]) { component[cur_node_id] = --components; stack[0] = cur_node_id; stack_size = 1; while (stack_size) { dglInt32_t *node, *edgeset, *edge; dglEdgesetTraverser_s et; dglInt32_t node_id = stack[stack_size - 1]; if (processed[node_id]) { stack_size--; order[order_size++] = node_id; continue; } processed[node_id] = 1; node = dglGetNode(graph, node_id); edgeset = dglNodeGet_OutEdgeset(graph, node); dglEdgeset_T_Initialize(&et, graph, edgeset); for (edge = dglEdgeset_T_First(&et); edge; edge = dglEdgeset_T_Next(&et)) { dglInt32_t to; to = dglNodeGet_Id(graph, dglEdgeGet_Tail(graph, edge)); if (!component[to]) { component[to] = components; /* do not go through closed nodes */ if (have_node_costs) { memcpy(&ncost, dglNodeGet_Attr(graph, dglEdgeGet_Tail(graph, edge)), sizeof(ncost)); } if (ncost < 0) processed[to] = 1; stack[stack_size++] = to; } } dglEdgeset_T_Release(&et); } } } dglNode_T_Release(&nt); components = 0; dglNode_T_Initialize(&nt, graph); while (order_size) { dglInt32_t cur_node_id = order[--order_size]; int cur_comp = component[cur_node_id]; if (cur_comp < 1) { component[cur_node_id] = ++components; stack[0] = cur_node_id; stack_size = 1; while (stack_size) { dglInt32_t *node, *edgeset, *edge; dglEdgesetTraverser_s et; dglInt32_t node_id = stack[--stack_size]; node = dglGetNode(graph, node_id); edgeset = dglNodeGet_InEdgeset(graph, node); dglEdgeset_T_Initialize(&et, graph, edgeset); for (edge = dglEdgeset_T_First(&et); edge; edge = dglEdgeset_T_Next(&et)) { dglInt32_t to; to = dglNodeGet_Id(graph, dglEdgeGet_Head(graph, edge)); if (component[to] == cur_comp) { component[to] = components; /* do not go through closed nodes */ if (have_node_costs) { memcpy(&ncost, dglNodeGet_Attr(graph, dglEdgeGet_Head(graph, edge)), sizeof(ncost)); } if (ncost >= 0) stack[stack_size++] = to; } } dglEdgeset_T_Release(&et); } } } dglNode_T_Release(&nt); G_free(stack); G_free(order); G_free(processed); return components; }