main.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. /****************************************************************
  2. *
  3. * MODULE: v.net.alloc
  4. *
  5. * AUTHOR(S): Radim Blazek
  6. * Stepan Turek <stepan.turek seznam.cz> (turns support)
  7. *
  8. * PURPOSE: Allocate subnets for nearest centers
  9. *
  10. * COPYRIGHT: (C) 2001, 2014 by the GRASS Development Team
  11. *
  12. * This program is free software under the
  13. * GNU General Public License (>=v2).
  14. * Read the file COPYING that comes with GRASS
  15. * for details.
  16. *
  17. ****************************************************************/
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <time.h>
  21. #include <grass/gis.h>
  22. #include <grass/vector.h>
  23. #include <grass/dbmi.h>
  24. #include <grass/glocale.h>
  25. typedef struct
  26. {
  27. int cat; /* category number */
  28. int node; /* node number */
  29. } CENTER;
  30. typedef struct
  31. {
  32. int center; /* neares center, initially -1 */
  33. double cost; /* costs from this center, initially not undefined */
  34. } NODE;
  35. int main(int argc, char **argv)
  36. {
  37. int i, j, ret, center, line, center1, center2;
  38. int nlines, nnodes, type, ltype, afield, nfield, geo, cat, tfield,
  39. tucfield;
  40. int node1, node2;
  41. double cost, e1cost, e2cost, n1cost, n2cost, s1cost, s2cost, l, l1, l2;
  42. struct Option *map, *output;
  43. struct Option *afield_opt, *nfield_opt, *afcol, *abcol, *ncol, *type_opt,
  44. *term_opt, *tfield_opt, *tucfield_opt;
  45. struct Flag *geo_f, *turntable_f;
  46. struct GModule *module;
  47. struct Map_info Map, Out;
  48. struct cat_list *catlist;
  49. CENTER *Centers = NULL;
  50. int acenters = 0, ncenters = 0;
  51. NODE *Nodes;
  52. struct line_cats *Cats;
  53. struct line_pnts *Points, *SPoints;
  54. /* initialize GIS environment */
  55. G_gisinit(argv[0]); /* reads grass env, stores program name to G_program_name() */
  56. /* initialize module */
  57. module = G_define_module();
  58. G_add_keyword(_("vector"));
  59. G_add_keyword(_("network"));
  60. G_add_keyword(_("allocation"));
  61. module->label =
  62. _("Allocates subnets for nearest centers (direction from center).");
  63. module->description =
  64. _("center node must be opened (costs >= 0). "
  65. "Costs of center node are used in calculation");
  66. map = G_define_standard_option(G_OPT_V_INPUT);
  67. output = G_define_standard_option(G_OPT_V_OUTPUT);
  68. term_opt = G_define_standard_option(G_OPT_V_CATS);
  69. term_opt->key = "ccats";
  70. term_opt->required = YES;
  71. term_opt->description =
  72. _("Categories of centers (points on nodes) to which net "
  73. "will be allocated, "
  74. "layer for this categories is given by nlayer option");
  75. afield_opt = G_define_standard_option(G_OPT_V_FIELD);
  76. afield_opt->key = "alayer";
  77. afield_opt->answer = "1";
  78. afield_opt->required = YES;
  79. afield_opt->label = _("Arc layer");
  80. type_opt = G_define_standard_option(G_OPT_V_TYPE);
  81. type_opt->options = "line,boundary";
  82. type_opt->answer = "line,boundary";
  83. type_opt->required = YES;
  84. type_opt->label = _("Arc type");
  85. nfield_opt = G_define_standard_option(G_OPT_V_FIELD);
  86. nfield_opt->key = "nlayer";
  87. nfield_opt->answer = "2";
  88. nfield_opt->required = YES;
  89. nfield_opt->label = _("Node layer");
  90. afcol = G_define_option();
  91. afcol->key = "afcolumn";
  92. afcol->type = TYPE_STRING;
  93. afcol->required = NO;
  94. afcol->description = _("Arc forward/both direction(s) cost column (number)");
  95. afcol->guisection = _("Cost");
  96. abcol = G_define_option();
  97. abcol->key = "abcolumn";
  98. abcol->type = TYPE_STRING;
  99. abcol->required = NO;
  100. abcol->description = _("Arc backward direction cost column (number)");
  101. abcol->guisection = _("Cost");
  102. ncol = G_define_option();
  103. ncol->key = "ncolumn";
  104. ncol->type = TYPE_STRING;
  105. ncol->required = NO;
  106. ncol->description = _("Node cost column (number)");
  107. ncol->guisection = _("Cost");
  108. turntable_f = G_define_flag();
  109. turntable_f->key = 't';
  110. turntable_f->description = _("Use turntable");
  111. turntable_f->guisection = _("Turntable");
  112. tfield_opt = G_define_standard_option(G_OPT_V_FIELD);
  113. tfield_opt->key = "tlayer";
  114. tfield_opt->answer = "3";
  115. tfield_opt->label = _("Layer with turntable");
  116. tfield_opt->description =
  117. _("Relevant only with -t flag");
  118. tfield_opt->guisection = _("Turntable");
  119. tucfield_opt = G_define_standard_option(G_OPT_V_FIELD);
  120. tucfield_opt->key = "tuclayer";
  121. tucfield_opt->answer = "4";
  122. tucfield_opt->label = _("Layer with unique categories used in turntable");
  123. tucfield_opt->description =
  124. _("Relevant only with -t flag");
  125. tucfield_opt->guisection = _("Turntable");
  126. geo_f = G_define_flag();
  127. geo_f->key = 'g';
  128. geo_f->description =
  129. _("Use geodesic calculation for longitude-latitude locations");
  130. if (G_parser(argc, argv))
  131. exit(EXIT_FAILURE);
  132. Vect_check_input_output_name(map->answer, output->answer, G_FATAL_EXIT);
  133. Cats = Vect_new_cats_struct();
  134. Points = Vect_new_line_struct();
  135. SPoints = Vect_new_line_struct();
  136. type = Vect_option_to_types(type_opt);
  137. catlist = Vect_new_cat_list();
  138. Vect_str_to_cat_list(term_opt->answer, catlist);
  139. if (geo_f->answer)
  140. geo = 1;
  141. else
  142. geo = 0;
  143. Vect_set_open_level(2);
  144. if (Vect_open_old(&Map, map->answer, "") < 0)
  145. G_fatal_error(_("Unable to open vector map <%s>"), map->answer);
  146. afield = Vect_get_field_number(&Map, afield_opt->answer);
  147. nfield = Vect_get_field_number(&Map, nfield_opt->answer);
  148. tfield = Vect_get_field_number(&Map, tfield_opt->answer);
  149. tucfield = Vect_get_field_number(&Map, tucfield_opt->answer);
  150. /* Build graph */
  151. if (turntable_f->answer)
  152. Vect_net_ttb_build_graph(&Map, type, afield, nfield, tfield, tucfield,
  153. afcol->answer, abcol->answer, ncol->answer,
  154. geo, 0);
  155. else
  156. Vect_net_build_graph(&Map, type, afield, nfield, afcol->answer,
  157. abcol->answer, ncol->answer, geo, 0);
  158. nnodes = Vect_get_num_nodes(&Map);
  159. nlines = Vect_get_num_lines(&Map);
  160. /* Create list of centers based on list of categories */
  161. for (i = 1; i <= nlines; i++) {
  162. int node;
  163. ltype = Vect_get_line_type(&Map, i);
  164. if (!(ltype & GV_POINT))
  165. continue;
  166. Vect_read_line(&Map, Points, Cats, i);
  167. node =
  168. Vect_find_node(&Map, Points->x[0], Points->y[0], Points->z[0], 0,
  169. 0);
  170. if (!node) {
  171. G_warning(_("Point is not connected to the network"));
  172. continue;
  173. }
  174. if (!(Vect_cat_get(Cats, nfield, &cat)))
  175. continue;
  176. if (Vect_cat_in_cat_list(cat, catlist)) {
  177. Vect_net_get_node_cost(&Map, node, &n1cost);
  178. if (n1cost == -1) { /* closed */
  179. G_warning("Centre at closed node (costs = -1) ignored");
  180. }
  181. else {
  182. if (acenters == ncenters) {
  183. acenters += 1;
  184. Centers =
  185. (CENTER *) G_realloc(Centers,
  186. acenters * sizeof(CENTER));
  187. }
  188. Centers[ncenters].cat = cat;
  189. Centers[ncenters].node = node;
  190. G_debug(2, "centre = %d node = %d cat = %d", ncenters,
  191. node, cat);
  192. ncenters++;
  193. }
  194. }
  195. }
  196. G_message(_("Number of centers: [%d] (nlayer: [%d])"), ncenters, nfield);
  197. if (ncenters == 0)
  198. G_warning(_("Not enough centers for selected nlayer. "
  199. "Nothing will be allocated."));
  200. /* alloc and reset space for all lines */
  201. if (turntable_f->answer) {
  202. /* if turntable is used we are looking for lines as destinations, not the intersections (nodes) */
  203. Nodes = (NODE *) G_calloc((nlines * 2 + 2), sizeof(NODE));
  204. for (i = 2; i <= (nlines * 2 + 2); i++) {
  205. Nodes[i].center = -1;/* NOTE: first two items of Nodes are not used */
  206. }
  207. }
  208. else {
  209. Nodes = (NODE *) G_calloc((nnodes + 1), sizeof(NODE));
  210. for (i = 1; i <= nnodes; i++) {
  211. Nodes[i].center = -1;
  212. }
  213. }
  214. /* Fill Nodes by nearest center and costs from that center */
  215. G_message(_("Calculating costs from centers ..."));
  216. for (center = 0; center < ncenters; center++) {
  217. G_percent(center, ncenters, 1);
  218. node1 = Centers[center].node;
  219. Vect_net_get_node_cost(&Map, node1, &n1cost);
  220. G_debug(2, "center = %d node = %d cat = %d", center, node1,
  221. Centers[center].cat);
  222. if (turntable_f->answer)
  223. for (line = 1; line <= nlines; line++) {
  224. G_debug(5, " node1 = %d line = %d", node1, line);
  225. Vect_net_get_node_cost(&Map, line, &n2cost);
  226. /* closed, left it as not attached */
  227. if (Vect_read_line(&Map, Points, Cats, line) < 0)
  228. continue;
  229. if (Vect_get_line_type(&Map, line) != GV_LINE)
  230. continue;
  231. if (!Vect_cat_get(Cats, tucfield, &cat))
  232. continue;
  233. for (j = 0; j < 2; j++) {
  234. if (j == 1)
  235. cat *= -1;
  236. ret =
  237. Vect_net_ttb_shortest_path(&Map, node1, 0, cat, 1,
  238. tucfield, NULL,
  239. &cost);
  240. if (ret == -1) {
  241. continue;
  242. } /* node unreachable */
  243. /* We must add center node costs (not calculated by Vect_net_shortest_path() ), but
  244. * only if center and node are not identical, because at the end node cost is add later */
  245. if (ret != 1)
  246. cost += n1cost;
  247. G_debug(5,
  248. "Arc nodes: %d %d cost: %f (x old cent: %d old cost %f",
  249. node1, line, cost, Nodes[line * 2 + j].center,
  250. Nodes[line * 2 + j].cost);
  251. if (Nodes[line * 2 + j].center == -1 ||
  252. cost < Nodes[line * 2 + j].cost) {
  253. Nodes[line * 2 + j].cost = cost;
  254. Nodes[line * 2 + j].center = center;
  255. }
  256. }
  257. }
  258. else
  259. for (node2 = 1; node2 <= nnodes; node2++) {
  260. G_debug(5, " node1 = %d node2 = %d", node1, node2);
  261. Vect_net_get_node_cost(&Map, node2, &n2cost);
  262. if (n2cost == -1) {
  263. continue;
  264. } /* closed, left it as not attached */
  265. ret = Vect_net_shortest_path(&Map, node1, node2, NULL, &cost);
  266. if (ret == -1) {
  267. continue;
  268. } /* node unreachable */
  269. /* We must add center node costs (not calculated by Vect_net_shortest_path() ), but
  270. * only if center and node are not identical, because at the end node cost is add later */
  271. if (node1 != node2)
  272. cost += n1cost;
  273. G_debug(5,
  274. "Arc nodes: %d %d cost: %f (x old cent: %d old cost %f",
  275. node1, node2, cost, Nodes[node2].center,
  276. Nodes[node2].cost);
  277. if (Nodes[node2].center == -1 || cost < Nodes[node2].cost) {
  278. Nodes[node2].cost = cost;
  279. Nodes[node2].center = center;
  280. }
  281. }
  282. }
  283. G_percent(1, 1, 1);
  284. /* Write arcs to new map */
  285. if (Vect_open_new(&Out, output->answer, Vect_is_3d(&Map)) < 0)
  286. G_fatal_error(_("Unable to create vector map <%s>"), output->answer);
  287. Vect_hist_command(&Out);
  288. nlines = Vect_get_num_lines(&Map);
  289. for (line = 1; line <= nlines; line++) {
  290. ltype = Vect_read_line(&Map, Points, NULL, line);
  291. if (!(ltype & type)) {
  292. continue;
  293. }
  294. if (turntable_f->answer) {
  295. center1 = Nodes[line * 2].center;
  296. center2 = Nodes[line * 2 + 1].center;
  297. s1cost = Nodes[line * 2].cost;
  298. s2cost = Nodes[line * 2 + 1].cost;
  299. n1cost = n2cost = 0;
  300. }
  301. else {
  302. Vect_get_line_nodes(&Map, line, &node1, &node2);
  303. center1 = Nodes[node1].center;
  304. center2 = Nodes[node2].center;
  305. s1cost = Nodes[node1].cost;
  306. s2cost = Nodes[node2].cost;
  307. Vect_net_get_node_cost(&Map, node1, &n1cost);
  308. Vect_net_get_node_cost(&Map, node2, &n2cost);
  309. }
  310. Vect_net_get_line_cost(&Map, line, GV_FORWARD, &e1cost);
  311. Vect_net_get_line_cost(&Map, line, GV_BACKWARD, &e2cost);
  312. G_debug(3, "Line %d:", line);
  313. G_debug(3, "Arc centers: %d %d (nodes: %d %d)", center1, center2,
  314. node1, node2);
  315. G_debug(3, " s1cost = %f n1cost = %f e1cost = %f", s1cost, n1cost,
  316. e1cost);
  317. G_debug(3, " s2cost = %f n2cost = %f e2cost = %f", s2cost, n2cost,
  318. e2cost);
  319. Vect_reset_cats(Cats);
  320. /* First check if arc is reachable from at least one side */
  321. if ((center1 != -1 && n1cost != -1 && e1cost != -1) ||
  322. (center2 != -1 && n2cost != -1 && e2cost != -1)) {
  323. /* Line is reachable at least from one side */
  324. G_debug(3, " -> arc is reachable");
  325. if (center1 == center2) { /* both nodes in one area -> whole arc in one area */
  326. if (center1 != -1)
  327. cat = Centers[center1].cat; /* line reachable */
  328. else
  329. cat = Centers[center2].cat;
  330. Vect_cat_set(Cats, 1, cat);
  331. Vect_write_line(&Out, ltype, Points, Cats);
  332. }
  333. else { /* each node in different area */
  334. /* Check if direction is reachable */
  335. if (center1 == -1 || n1cost == -1 || e1cost == -1) { /* closed from first node */
  336. G_debug(3,
  337. " -> arc is not reachable from 1. node -> alloc to 2. node");
  338. cat = Centers[center2].cat;
  339. Vect_cat_set(Cats, 1, cat);
  340. Vect_write_line(&Out, ltype, Points, Cats);
  341. continue;
  342. }
  343. else if (center2 == -1 || n2cost == -1 || e2cost == -1) { /* closed from second node */
  344. G_debug(3,
  345. " -> arc is not reachable from 2. node -> alloc to 1. node");
  346. cat = Centers[center1].cat;
  347. Vect_cat_set(Cats, 1, cat);
  348. Vect_write_line(&Out, ltype, Points, Cats);
  349. continue;
  350. }
  351. /* Now we know that arc is reachable from both sides */
  352. /* Add costs of node to starting costs */
  353. s1cost += n1cost;
  354. s2cost += n2cost;
  355. /* Check if s1cost + e1cost <= s2cost or s2cost + e2cost <= s1cost !
  356. * Note this check also possibility of (e1cost + e2cost) = 0 */
  357. if (s1cost + e1cost <= s2cost) { /* whole arc reachable from node1 */
  358. cat = Centers[center1].cat;
  359. Vect_cat_set(Cats, 1, cat);
  360. Vect_write_line(&Out, ltype, Points, Cats);
  361. }
  362. else if (s2cost + e2cost <= s1cost) { /* whole arc reachable from node2 */
  363. cat = Centers[center2].cat;
  364. Vect_cat_set(Cats, 1, cat);
  365. Vect_write_line(&Out, ltype, Points, Cats);
  366. }
  367. else { /* split */
  368. /* Calculate relative costs - we expect that costs along the line do not change */
  369. l = Vect_line_length(Points);
  370. e1cost /= l;
  371. e2cost /= l;
  372. G_debug(3, " -> s1cost = %f e1cost = %f", s1cost,
  373. e1cost);
  374. G_debug(3, " -> s2cost = %f e2cost = %f", s2cost,
  375. e2cost);
  376. /* Costs from both centers to the splitting point must be equal:
  377. * s1cost + l1 * e1cost = s2cost + l2 * e2cost */
  378. l1 = (l * e2cost - s1cost + s2cost) / (e1cost + e2cost);
  379. l2 = l - l1;
  380. G_debug(3, "l = %f l1 = %f l2 = %f", l, l1, l2);
  381. /* First segment */
  382. ret = Vect_line_segment(Points, 0, l1, SPoints);
  383. if (ret == 0) {
  384. G_warning(_
  385. ("Cannot get line segment, segment out of line"));
  386. }
  387. else {
  388. cat = Centers[center1].cat;
  389. Vect_cat_set(Cats, 1, cat);
  390. Vect_write_line(&Out, ltype, SPoints, Cats);
  391. }
  392. /* Second segment */
  393. ret = Vect_line_segment(Points, l1, l, SPoints);
  394. if (ret == 0) {
  395. G_warning(_
  396. ("Cannot get line segment, segment out of line"));
  397. }
  398. else {
  399. Vect_reset_cats(Cats);
  400. cat = Centers[center2].cat;
  401. Vect_cat_set(Cats, 1, cat);
  402. Vect_write_line(&Out, ltype, SPoints, Cats);
  403. }
  404. }
  405. }
  406. }
  407. else {
  408. /* arc is not reachable */
  409. G_debug(3, " -> arc is not reachable");
  410. Vect_write_line(&Out, ltype, Points, Cats);
  411. }
  412. }
  413. Vect_build(&Out);
  414. /* Free, ... */
  415. G_free(Nodes);
  416. G_free(Centers);
  417. Vect_close(&Map);
  418. Vect_close(&Out);
  419. exit(EXIT_SUCCESS);
  420. }