main.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682
  1. /****************************************************************
  2. *
  3. * MODULE: v.net.steiner
  4. *
  5. * AUTHOR(S): Radim Blazek
  6. *
  7. * PURPOSE: Find Steiner tree for network
  8. *
  9. * COPYRIGHT: (C) 2001 by the GRASS Development Team
  10. *
  11. * This program is free software under the
  12. * GNU General Public License (>=v2).
  13. * Read the file COPYING that comes with GRASS
  14. * for details.
  15. *
  16. **************************************************************/
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <time.h>
  20. #include <grass/gis.h>
  21. #include <grass/vector.h>
  22. #include <grass/dbmi.h>
  23. #include <grass/glocale.h>
  24. /* costs between 2 terminals */
  25. typedef struct
  26. {
  27. int term1, term2;
  28. double cost;
  29. } COST;
  30. int nterms; /* number of terminals */
  31. int nnodes; /* number of nodes */
  32. int *terms; /* array of 1. terminals; 2. accepted steiner points; 3. tested steiner point */
  33. COST *term_costs; /* costs between terminals */
  34. COST *sp_costs; /* costs between StP and terminals */
  35. int *comps; /* numbers of component, the terminal was assigned to */
  36. /* pointer to array of pointers to costs to other nodes, matrix: from-to, from < to:
  37. * 1-2 1-3 1-4 ... 1-nnodes
  38. * 2-3 2-4 ... 2-nnodes
  39. * 3-4 ... 3-nnodes
  40. * ...
  41. * (nnodes - 1)-nnodes
  42. * !!! init costs for from or to node, before this cost is read by init_node_costs();
  43. */
  44. double **nodes_costs;
  45. int cmp(const void *, const void *);
  46. /* Init all costs to/from given node */
  47. int init_node_costs(struct Map_info *Map, int from)
  48. {
  49. int to, ret, row, col;
  50. double cost;
  51. G_verbose_message(_("Init costs from node %d"), from);
  52. for (to = 1; to <= nnodes; to++) {
  53. if (from == to)
  54. continue;
  55. ret = Vect_net_shortest_path(Map, from, to, NULL, &cost);
  56. if (ret == -1) {
  57. G_debug(1, "Destination node %d is unreachable from node %d\n", to, from);
  58. cost = -2;
  59. }
  60. if (from < to) {
  61. row = from - 1;
  62. col = to - from - 1;
  63. }
  64. else {
  65. row = to - 1;
  66. col = from - to - 1;
  67. }
  68. G_debug(3, "init costs %d - > %d = %f\n", from, to, cost);
  69. nodes_costs[row][col] = cost;
  70. }
  71. return 1;
  72. }
  73. /* Get cost from node to node.
  74. * From or to costs must be init before!!!
  75. * Returns: 1 - ok, 0 - not reachable
  76. */
  77. int get_node_costs(int from, int to, double *cost)
  78. {
  79. int row, col, tmp;
  80. if (from == to) {
  81. *cost = 0;
  82. return 1;
  83. }
  84. if (from > to) {
  85. tmp = from;
  86. from = to;
  87. to = tmp;
  88. }
  89. row = from - 1;
  90. col = to - from - 1;
  91. if (nodes_costs[row][col] == -2) {
  92. *cost = PORT_DOUBLE_MAX;
  93. return 0;
  94. }
  95. *cost = nodes_costs[row][col];
  96. return 1;
  97. }
  98. /* Calculate costs for MST on given set of terminals.
  99. * If AList / NList is not NULL, list of arcs / nodes in MST is created
  100. * Note: qsort() from more (say >30) terminals, takes long time (most of mst()).
  101. * To improve the speed, there are used two sorted queues of costs:
  102. * 1. for all combinations of in trms
  103. * 2. from 'sp' to all other terminals
  104. * Because 1. is sorted only if new sp as added to list of terminals,
  105. * and 2. is much shorter than 1., a lot of time is saved.
  106. */
  107. int mst(struct Map_info *Map, int *trms, int ntrms, /* array of terminal, number of terminals */
  108. double *cst, double max_cst, /* cost, maximum cost */
  109. struct ilist *AList, struct ilist *NList, /* list of arcs/nodes in ST */
  110. int sp, /* Steiner point (node) to be tested with terminals, (0 = ignore) */
  111. int rebuild)
  112. { /* rebuild the sorted list of costs for terminals */
  113. int i, j, node1, node2, com1, com2, t1, t2, line;
  114. static int k;
  115. int tcpos, scpos; /* current position in the term_costs / sp_costs */
  116. double tcst;
  117. struct ilist *List;
  118. int nsteps, quse;
  119. int nall; /* number of terminals + sp ( if used ) */
  120. if (AList != NULL) {
  121. Vect_reset_list(AList);
  122. }
  123. List = Vect_new_list();
  124. /* Create sorted array for all combinations of terms */
  125. if (rebuild) {
  126. k = 0;
  127. for (i = 0; i < ntrms; i++) {
  128. for (j = i + 1; j < ntrms; j++) {
  129. term_costs[k].term1 = i;
  130. term_costs[k].term2 = j;
  131. get_node_costs(trms[i], trms[j], &tcst);
  132. term_costs[k].cost = tcst;
  133. k++;
  134. }
  135. }
  136. qsort((void *)term_costs, k, sizeof(COST), cmp); /* this takes most of a time in mst() */
  137. for (i = 0; i < k; i++) {
  138. G_debug(3, " %d - %d cost = %f\n", term_costs[i].term1,
  139. term_costs[i].term2, term_costs[i].cost);
  140. }
  141. }
  142. /* Create sorted array for all combinations of sp -> terms */
  143. if (sp > 0) {
  144. for (i = 0; i < ntrms; i++) {
  145. sp_costs[i].term1 = -1; /* not needed */
  146. sp_costs[i].term2 = i;
  147. get_node_costs(sp, trms[i], &tcst);
  148. sp_costs[i].cost = tcst;
  149. }
  150. qsort((void *)sp_costs, ntrms, sizeof(COST), cmp);
  151. for (i = 0; i < ntrms; i++) {
  152. G_debug(3, " %d - %d cost = %f\n", sp_costs[i].term1,
  153. sp_costs[i].term2, sp_costs[i].cost);
  154. }
  155. }
  156. tcst = 0;
  157. /* MST has number_of_terminals-1 arcs */
  158. if (sp > 0) {
  159. nall = ntrms + 1;
  160. nsteps = ntrms; /* i.e. + one StP */
  161. }
  162. else {
  163. nall = ntrms;
  164. nsteps = ntrms - 1;
  165. }
  166. G_debug(1, "nall = %d\n", nall);
  167. for (i = 0; i < nall; i++)
  168. comps[i] = 0;
  169. tcpos = 0;
  170. scpos = 0;
  171. G_debug(2, "nsteps = %d\n", nsteps);
  172. for (i = 0; i < nsteps; i++) {
  173. G_debug(2, "step = %d\n", i);
  174. /* Take the best (lowest costs, no cycle) from both queues */
  175. /* For both queues go to next lowest costs without cycle */
  176. /* treminal costs */
  177. for (j = tcpos; j < k; j++) {
  178. t1 = term_costs[j].term1;
  179. t2 = term_costs[j].term2;
  180. com1 = comps[t1];
  181. com2 = comps[t2];
  182. if (com1 != com2 || com1 == 0) { /* will not create cycle -> candidate */
  183. tcpos = j;
  184. break;
  185. }
  186. }
  187. if (j == k) { /* arc without cycle not found */
  188. tcpos = -1;
  189. }
  190. /* StP costs */
  191. if (sp > 0) {
  192. for (j = scpos; j < ntrms; j++) {
  193. t1 = ntrms; /* StP is on first fre position */
  194. t2 = sp_costs[j].term2;
  195. com1 = comps[t1];
  196. com2 = comps[t2];
  197. G_debug(3, "scpos: j = %d comps(%d) = %d coms(%d) = %d\n", j,
  198. t1, com1, t2, com2);
  199. if (com1 != com2 || com1 == 0) { /* will not create cycle -> candidate */
  200. scpos = j;
  201. G_debug(3, " ok -> scpos = %d\n", scpos);
  202. break;
  203. }
  204. }
  205. if (j == ntrms) { /* arc without cycle not found */
  206. scpos = -1;
  207. }
  208. }
  209. else {
  210. scpos = -1;
  211. }
  212. /* Do not access invalid items even for debugging */
  213. if (tcpos != -1 && scpos != -1)
  214. G_debug(3, "tcost = %f, scost = %f\n", term_costs[tcpos].cost,
  215. sp_costs[scpos].cost);
  216. /* Now we have positions set on lowest costs in each queue or -1 if no more/not used */
  217. if (tcpos >= 0 && scpos >= 0) {
  218. if (term_costs[tcpos].cost < sp_costs[scpos].cost)
  219. quse = 1; /* use terms queue */
  220. else
  221. quse = 2; /* use sp queue */
  222. }
  223. else if (tcpos >= 0) {
  224. quse = 1; /* use terms queue */
  225. }
  226. else {
  227. quse = 2; /* use sp queue */
  228. }
  229. /* Now we know from which queue take next arc -> add arc to components */
  230. if (quse == 1) {
  231. t1 = term_costs[tcpos].term1;
  232. t2 = term_costs[tcpos].term2;
  233. tcst += term_costs[tcpos].cost;
  234. tcpos++;
  235. }
  236. else {
  237. t1 = ntrms;
  238. t2 = sp_costs[scpos].term2;
  239. tcst += sp_costs[scpos].cost;
  240. scpos++;
  241. }
  242. G_debug(3, "quse = %d t1 = %d t2 = %d\n", quse, t1, t2);
  243. G_debug(3, "tcst = %f (max = %f)\n", tcst, max_cst);
  244. com1 = comps[t1];
  245. com2 = comps[t2];
  246. comps[t1] = i + 1;
  247. comps[t2] = i + 1;
  248. G_debug(3, "comps(%d) = %d coms(%d) = %d\n", t1, i + 1, t2, i + 1);
  249. /* reset connected branches */
  250. for (j = 0; j < nall; j++) {
  251. if (comps[j] == com1 && com1 != 0)
  252. comps[j] = i + 1;
  253. if (comps[j] == com2 && com2 != 0)
  254. comps[j] = i + 1;
  255. }
  256. if (tcst > max_cst) {
  257. G_debug(3, "cost > max -> return\n");
  258. *cst = PORT_DOUBLE_MAX;
  259. return 1;
  260. }
  261. /* add to list of arcs */
  262. if (AList != NULL) {
  263. node1 = trms[t1];
  264. node2 = trms[t2];
  265. Vect_net_shortest_path(Map, node1, node2, List, NULL);
  266. for (j = 0; j < List->n_values; j++) {
  267. Vect_list_append(AList, abs(List->value[j]));
  268. }
  269. }
  270. }
  271. /* create list of nodes */
  272. if (NList != NULL) {
  273. Vect_reset_list(NList);
  274. for (i = 0; i < AList->n_values; i++) {
  275. line = AList->value[i];
  276. Vect_get_line_nodes(Map, line, &node1, &node2);
  277. Vect_list_append(NList, node1);
  278. Vect_list_append(NList, node2);
  279. }
  280. }
  281. *cst = tcst;
  282. Vect_destroy_list(List);
  283. return 1;
  284. }
  285. int main(int argc, char **argv)
  286. {
  287. int i, j, k, ret;
  288. int nlines, type, ltype, afield, tfield, geo, cat;
  289. int sp, nsp, nspused, node, line;
  290. struct Option *map, *output, *afield_opt, *tfield_opt, *afcol, *type_opt,
  291. *term_opt, *nsp_opt;
  292. struct Flag *geo_f;
  293. struct GModule *module;
  294. struct Map_info Map, Out;
  295. int *testnode; /* array all nodes: 1 - should be tested as Steiner,
  296. * 0 - no need to test (unreachable or terminal) */
  297. struct ilist *TList; /* list of terminal nodes */
  298. struct ilist *StArcs; /* list of arcs on Steiner tree */
  299. struct ilist *StNodes; /* list of nodes on Steiner tree */
  300. struct boxlist *pointlist;
  301. double cost, tmpcost;
  302. struct cat_list *Clist;
  303. struct line_cats *Cats;
  304. struct line_pnts *Points;
  305. /* Initialize the GIS calls */
  306. G_gisinit(argv[0]);
  307. module = G_define_module();
  308. G_add_keyword(_("vector"));
  309. G_add_keyword(_("network"));
  310. G_add_keyword(_("steiner tree"));
  311. module->label =
  312. _("Creates Steiner tree for the network and given terminals.");
  313. module->description =
  314. _("Note that 'Minimum Steiner Tree' problem is NP-hard "
  315. "and heuristic algorithm is used in this module so "
  316. "the result may be sub optimal.");
  317. map = G_define_standard_option(G_OPT_V_INPUT);
  318. output = G_define_standard_option(G_OPT_V_OUTPUT);
  319. type_opt = G_define_standard_option(G_OPT_V_TYPE);
  320. type_opt->key = "arc_type";
  321. type_opt->options = "line,boundary";
  322. type_opt->answer = "line,boundary";
  323. type_opt->label = _("Arc type");
  324. afield_opt = G_define_standard_option(G_OPT_V_FIELD);
  325. afield_opt->key = "arc_layer";
  326. afield_opt->answer = "1";
  327. afield_opt->label = _("Arc layer");
  328. tfield_opt = G_define_standard_option(G_OPT_V_FIELD);
  329. tfield_opt->key = "node_layer";
  330. tfield_opt->answer = "2";
  331. tfield_opt->label = _("Node layer (used for terminals)");
  332. afcol = G_define_option();
  333. afcol->key = "acolumn";
  334. afcol->type = TYPE_STRING;
  335. afcol->required = NO;
  336. afcol->description = _("Arcs' cost column (for both directions)");
  337. term_opt = G_define_standard_option(G_OPT_V_CATS);
  338. term_opt->key = "terminal_cats";
  339. term_opt->required = YES;
  340. term_opt->description =
  341. _("Categories of points on terminals (layer is specified by nlayer)");
  342. nsp_opt = G_define_option();
  343. nsp_opt->key = "npoints";
  344. nsp_opt->type = TYPE_INTEGER;
  345. nsp_opt->required = NO;
  346. nsp_opt->multiple = NO;
  347. nsp_opt->answer = "-1";
  348. nsp_opt->description = _("Number of Steiner points (-1 for all possible)");
  349. geo_f = G_define_flag();
  350. geo_f->key = 'g';
  351. geo_f->description =
  352. _("Use geodesic calculation for longitude-latitude locations");
  353. if (G_parser(argc, argv))
  354. exit(EXIT_FAILURE);
  355. Cats = Vect_new_cats_struct();
  356. Points = Vect_new_line_struct();
  357. type = Vect_option_to_types(type_opt);
  358. afield = atoi(afield_opt->answer);
  359. TList = Vect_new_list();
  360. StArcs = Vect_new_list();
  361. StNodes = Vect_new_list();
  362. Clist = Vect_new_cat_list();
  363. tfield = atoi(tfield_opt->answer);
  364. Vect_str_to_cat_list(term_opt->answer, Clist);
  365. G_debug(1, "Imput categories:\n");
  366. for (i = 0; i < Clist->n_ranges; i++) {
  367. G_debug(1, "%d - %d\n", Clist->min[i], Clist->max[i]);
  368. }
  369. if (geo_f->answer)
  370. geo = 1;
  371. else
  372. geo = 0;
  373. Vect_check_input_output_name(map->answer, output->answer, G_FATAL_EXIT);
  374. Vect_set_open_level(2);
  375. if (Vect_open_old(&Map, map->answer, "") < 0)
  376. G_fatal_error(_("Unable to open vector map <%s>"), map->answer);
  377. nnodes = Vect_get_num_nodes(&Map);
  378. nlines = Vect_get_num_lines(&Map);
  379. /* Create list of terminals based on list of categories */
  380. for (i = 1; i <= nlines; i++) {
  381. ltype = Vect_get_line_type(&Map, i);
  382. if (!(ltype & GV_POINT))
  383. continue;
  384. Vect_read_line(&Map, Points, Cats, i);
  385. if (!(Vect_cat_get(Cats, tfield, &cat)))
  386. continue;
  387. node = Vect_find_node(&Map, Points->x[0], Points->y[0], Points->z[0], 0, 0);
  388. if (!node) {
  389. G_warning(_("Point is not connected to the network (cat=%d)"), cat);
  390. continue;
  391. }
  392. if (Vect_cat_in_cat_list(cat, Clist)) {
  393. Vect_list_append(TList, node);
  394. }
  395. }
  396. nterms = TList->n_values;
  397. /* GTC Terminal refers to an Steiner tree endpoint */
  398. G_message(_("Number of terminals: %d\n"), nterms);
  399. if (nterms < 2) {
  400. /* GTC Terminal refers to an Steiner tree endpoint */
  401. G_fatal_error(_("Not enough terminals (< 2)"));
  402. }
  403. /* Number of steiner points */
  404. nsp = atoi(nsp_opt->answer);
  405. if (nsp > nterms - 2) {
  406. nsp = nterms - 2;
  407. G_warning(_("Requested number of Steiner points > than possible"));
  408. }
  409. else if (nsp == -1) {
  410. nsp = nterms - 2;
  411. }
  412. G_message(_("Number of Steiner points set to %d\n"), nsp);
  413. testnode = (int *)G_malloc((nnodes + 1) * sizeof(int));
  414. for (i = 1; i <= nnodes; i++)
  415. testnode[i] = 1;
  416. /* Alloc arrays of costs for nodes, first node at 1 (0 not used) */
  417. nodes_costs = (double **)G_malloc((nnodes) * sizeof(double *));
  418. for (i = 0; i < nnodes; i++) {
  419. nodes_costs[i] =
  420. (double *)G_malloc((nnodes - i) * sizeof(double));
  421. for (j = 0; j < nnodes - i; j++)
  422. nodes_costs[i][j] = -1; /* init, i.e. cost was not calculated yet */
  423. }
  424. /* alloc memory from each to each other (not directed) terminal */
  425. i = nterms + nterms - 2; /* max number of terms + Steiner points */
  426. comps = (int *)G_malloc(i * sizeof(int));
  427. i = i * (i - 1) / 2; /* number of combinations */
  428. term_costs = (COST *) G_malloc(i * sizeof(COST));
  429. /* alloc memory for costs from Stp to each other terminal */
  430. i = nterms + nterms - 2 - 1; /* max number of terms + Steiner points - 1 */
  431. sp_costs = (COST *) G_malloc(i * sizeof(COST));
  432. terms = (int *)G_malloc((nterms + nterms - 2) * sizeof(int)); /* i.e. +(nterms - 2) St Points */
  433. /* Create initial parts from list of terminals */
  434. G_debug(1, "List of terminal nodes (%d):\n", nterms);
  435. for (i = 0; i < nterms; i++) {
  436. G_debug(1, "%d\n", TList->value[i]);
  437. terms[i] = TList->value[i];
  438. testnode[terms[i]] = 0; /* do not test as Steiner */
  439. }
  440. /* Build graph */
  441. Vect_net_build_graph(&Map, type, afield, 0, afcol->answer, NULL, NULL,
  442. geo, 0);
  443. /* Init costs for all terminals */
  444. for (i = 0; i < nterms; i++)
  445. init_node_costs(&Map, terms[i]);
  446. /* Test if all terminal may be connected */
  447. for (i = 1; i < nterms; i++) {
  448. ret = get_node_costs(terms[0], terms[i], &cost);
  449. if (ret == 0) {
  450. /* GTC Terminal refers to an Steiner tree endpoint */
  451. G_fatal_error(_("Terminal at node [%d] cannot be connected "
  452. "to terminal at node [%d]"), terms[0], terms[i]);
  453. }
  454. }
  455. /* Remove not reachable from list of SP candidates */
  456. j = 0;
  457. for (i = 1; i <= nnodes; i++) {
  458. ret = get_node_costs(terms[0], i, &cost);
  459. if (ret == 0) {
  460. testnode[i] = 0;
  461. G_debug(2, "node %d removed from list of Steiner point candidates\n", i );
  462. j++;
  463. }
  464. }
  465. G_message(_("[%d] (not reachable) nodes removed from list "
  466. "of Steiner point candidates"), j);
  467. /* calc costs for terminals MST */
  468. ret = mst(&Map, terms, nterms, &cost, PORT_DOUBLE_MAX, NULL, NULL, 0, 1); /* no StP, rebuild */
  469. G_message(_("MST costs = %f"), cost);
  470. /* Go through all nodes and try to use as steiner points -> find that which saves most costs */
  471. nspused = 0;
  472. for (j = 0; j < nsp; j++) {
  473. sp = 0;
  474. G_verbose_message(_("Search for [%d]. Steiner point"), j + 1);
  475. for (i = 1; i <= nnodes; i++) {
  476. G_percent(i, nnodes, 1);
  477. if (testnode[i] == 0) {
  478. G_debug(3, "skip test for %d\n", i);
  479. continue;
  480. }
  481. ret =
  482. mst(&Map, terms, nterms + j, &tmpcost, cost, NULL, NULL, i,
  483. 0);
  484. G_debug(2, "cost = %f x %f\n", tmpcost, cost);
  485. if (tmpcost < cost) { /* sp candidate */
  486. G_debug(3,
  487. " steiner candidate node = %d mst = %f (x last = %f)\n",
  488. i, tmpcost, cost);
  489. sp = i;
  490. cost = tmpcost;
  491. }
  492. }
  493. if (sp > 0) {
  494. G_message(_("Steiner point at node [%d] was added "
  495. "to terminals (MST costs = %f)"), sp, cost);
  496. terms[nterms + j] = sp;
  497. init_node_costs(&Map, sp);
  498. testnode[sp] = 0;
  499. nspused++;
  500. /* rebuild for nex cycle */
  501. ret =
  502. mst(&Map, terms, nterms + nspused, &tmpcost, PORT_DOUBLE_MAX,
  503. NULL, NULL, 0, 1);
  504. }
  505. else { /* no steiner found */
  506. G_message(_("No Steiner point found -> leaving cycle"));
  507. break;
  508. }
  509. }
  510. G_message(_("Number of added Steiner points: %d "
  511. "(theoretic max is %d).\n"), nspused, nterms - 2);
  512. /* Build lists of arcs and nodes for final version */
  513. ret =
  514. mst(&Map, terms, nterms + nspused, &cost, PORT_DOUBLE_MAX, StArcs,
  515. StNodes, 0, 0);
  516. /* Calculate true costs, which may be lower than MST if steiner points were not used */
  517. if (nsp < nterms - 2) {
  518. G_message(_("Spanning tree costs on complete graph = %f\n"
  519. "(may be higher than resulting Steiner tree costs!!!)"),
  520. cost);
  521. }
  522. else
  523. G_message(_("Steiner tree costs = %f"), cost);
  524. /* Write arcs to new map */
  525. if (Vect_open_new(&Out, output->answer, Vect_is_3d(&Map)) < 0)
  526. G_fatal_error(_("Unable to create vector map <%s>"), output->answer);
  527. Vect_hist_command(&Out);
  528. G_debug(1, "Steiner tree:");
  529. G_debug(1, "Arcs' categories (layer %d, %d arcs):", afield,
  530. StArcs->n_values);
  531. for (i = 0; i < StArcs->n_values; i++) {
  532. line = StArcs->value[i];
  533. ltype = Vect_read_line(&Map, Points, Cats, line);
  534. Vect_write_line(&Out, ltype, Points, Cats);
  535. Vect_cat_get(Cats, afield, &cat);
  536. G_debug(1, "arc cat = %d", cat);
  537. }
  538. G_debug(1, "Nodes' categories (layer %d, %d nodes):", tfield,
  539. StNodes->n_values);
  540. k = 0;
  541. pointlist = Vect_new_boxlist(0);
  542. for (i = 0; i < StNodes->n_values; i++) {
  543. double x, y, z;
  544. struct bound_box box;
  545. node = StNodes->value[i];
  546. Vect_get_node_coor(&Map, node, &x, &y, &z);
  547. box.E = box.W = x;
  548. box.N = box.S = y;
  549. box.T = box.B = z;
  550. Vect_select_lines_by_box(&Map, &box, GV_POINT, pointlist);
  551. nlines = Vect_get_node_n_lines(&Map, node);
  552. for (j = 0; j < pointlist->n_values; j++) {
  553. line = pointlist->id[j];
  554. ltype = Vect_read_line(&Map, Points, Cats, line);
  555. if (!(ltype & GV_POINT))
  556. continue;
  557. if (!(Vect_cat_get(Cats, tfield, &cat)))
  558. continue;
  559. Vect_write_line(&Out, ltype, Points, Cats);
  560. G_debug(1, "node cat = %d", cat);
  561. k++;
  562. }
  563. }
  564. Vect_build(&Out);
  565. G_message(n_("A Steiner tree with %d arc has been built",
  566. "A Steiner tree with %d arcs has been built", StArcs->n_values),
  567. StArcs->n_values);
  568. /* Free, ... */
  569. Vect_destroy_list(StArcs);
  570. Vect_destroy_list(StNodes);
  571. Vect_close(&Map);
  572. Vect_close(&Out);
  573. exit(EXIT_SUCCESS);
  574. }
  575. int cmp(const void *pa, const void *pb)
  576. {
  577. COST *p1 = (COST *) pa;
  578. COST *p2 = (COST *) pb;
  579. if (p1->cost < p2->cost)
  580. return -1;
  581. if (p1->cost > p2->cost)
  582. return 1;
  583. return 0;
  584. }