main.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  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(_("cost 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 = "center_cats";
  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 = "arc_layer";
  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->key = "arc_type";
  82. type_opt->options = "line,boundary";
  83. type_opt->answer = "line,boundary";
  84. type_opt->required = YES;
  85. type_opt->label = _("Arc type");
  86. nfield_opt = G_define_standard_option(G_OPT_V_FIELD);
  87. nfield_opt->key = "node_layer";
  88. nfield_opt->answer = "2";
  89. nfield_opt->required = YES;
  90. nfield_opt->label = _("Node layer");
  91. afcol = G_define_option();
  92. afcol->key = "afcolumn";
  93. afcol->type = TYPE_STRING;
  94. afcol->required = NO;
  95. afcol->description = _("Arc forward/both direction(s) cost column (number)");
  96. afcol->guisection = _("Cost");
  97. abcol = G_define_option();
  98. abcol->key = "abcolumn";
  99. abcol->type = TYPE_STRING;
  100. abcol->required = NO;
  101. abcol->description = _("Arc backward direction cost column (number)");
  102. abcol->guisection = _("Cost");
  103. ncol = G_define_option();
  104. ncol->key = "node_column";
  105. ncol->type = TYPE_STRING;
  106. ncol->required = NO;
  107. ncol->description = _("Node cost column (number)");
  108. ncol->guisection = _("Cost");
  109. turntable_f = G_define_flag();
  110. turntable_f->key = 't';
  111. turntable_f->description = _("Use turntable");
  112. turntable_f->guisection = _("Turntable");
  113. tfield_opt = G_define_standard_option(G_OPT_V_FIELD);
  114. tfield_opt->key = "tlayer";
  115. tfield_opt->answer = "3";
  116. tfield_opt->label = _("Layer with turntable");
  117. tfield_opt->description =
  118. _("Relevant only with -t flag");
  119. tfield_opt->guisection = _("Turntable");
  120. tucfield_opt = G_define_standard_option(G_OPT_V_FIELD);
  121. tucfield_opt->key = "tuclayer";
  122. tucfield_opt->answer = "4";
  123. tucfield_opt->label = _("Layer with unique categories used in turntable");
  124. tucfield_opt->description =
  125. _("Relevant only with -t flag");
  126. tucfield_opt->guisection = _("Turntable");
  127. geo_f = G_define_flag();
  128. geo_f->key = 'g';
  129. geo_f->description =
  130. _("Use geodesic calculation for longitude-latitude locations");
  131. if (G_parser(argc, argv))
  132. exit(EXIT_FAILURE);
  133. Vect_check_input_output_name(map->answer, output->answer, G_FATAL_EXIT);
  134. Cats = Vect_new_cats_struct();
  135. Points = Vect_new_line_struct();
  136. SPoints = Vect_new_line_struct();
  137. type = Vect_option_to_types(type_opt);
  138. catlist = Vect_new_cat_list();
  139. Vect_str_to_cat_list(term_opt->answer, catlist);
  140. if (geo_f->answer)
  141. geo = 1;
  142. else
  143. geo = 0;
  144. Vect_set_open_level(2);
  145. if (Vect_open_old(&Map, map->answer, "") < 0)
  146. G_fatal_error(_("Unable to open vector map <%s>"), map->answer);
  147. afield = Vect_get_field_number(&Map, afield_opt->answer);
  148. nfield = Vect_get_field_number(&Map, nfield_opt->answer);
  149. tfield = Vect_get_field_number(&Map, tfield_opt->answer);
  150. tucfield = Vect_get_field_number(&Map, tucfield_opt->answer);
  151. /* Build graph */
  152. if (turntable_f->answer)
  153. Vect_net_ttb_build_graph(&Map, type, afield, nfield, tfield, tucfield,
  154. afcol->answer, abcol->answer, ncol->answer,
  155. geo, 0);
  156. else
  157. Vect_net_build_graph(&Map, type, afield, nfield, afcol->answer,
  158. abcol->answer, ncol->answer, geo, 0);
  159. nnodes = Vect_get_num_nodes(&Map);
  160. nlines = Vect_get_num_lines(&Map);
  161. /* Create list of centers based on list of categories */
  162. for (i = 1; i <= nlines; i++) {
  163. int node;
  164. ltype = Vect_get_line_type(&Map, i);
  165. if (!(ltype & GV_POINT))
  166. continue;
  167. Vect_read_line(&Map, Points, Cats, i);
  168. node =
  169. Vect_find_node(&Map, Points->x[0], Points->y[0], Points->z[0], 0,
  170. 0);
  171. if (!node) {
  172. G_warning(_("Point is not connected to the network"));
  173. continue;
  174. }
  175. if (!(Vect_cat_get(Cats, nfield, &cat)))
  176. continue;
  177. if (Vect_cat_in_cat_list(cat, catlist)) {
  178. Vect_net_get_node_cost(&Map, node, &n1cost);
  179. if (n1cost == -1) { /* closed */
  180. G_warning("Centre at closed node (costs = -1) ignored");
  181. }
  182. else {
  183. if (acenters == ncenters) {
  184. acenters += 1;
  185. Centers =
  186. (CENTER *) G_realloc(Centers,
  187. acenters * sizeof(CENTER));
  188. }
  189. Centers[ncenters].cat = cat;
  190. Centers[ncenters].node = node;
  191. G_debug(2, "centre = %d node = %d cat = %d", ncenters,
  192. node, cat);
  193. ncenters++;
  194. }
  195. }
  196. }
  197. G_message(_("Number of centers: [%d] (nlayer: [%d])"), ncenters, nfield);
  198. if (ncenters == 0)
  199. G_warning(_("Not enough centers for selected nlayer. "
  200. "Nothing will be allocated."));
  201. /* alloc and reset space for all lines */
  202. if (turntable_f->answer) {
  203. /* if turntable is used we are looking for lines as destinations, not the intersections (nodes) */
  204. Nodes = (NODE *) G_calloc((nlines * 2 + 2), sizeof(NODE));
  205. for (i = 2; i <= (nlines * 2 + 2); i++) {
  206. Nodes[i].center = -1;/* NOTE: first two items of Nodes are not used */
  207. }
  208. }
  209. else {
  210. Nodes = (NODE *) G_calloc((nnodes + 1), sizeof(NODE));
  211. for (i = 1; i <= nnodes; i++) {
  212. Nodes[i].center = -1;
  213. }
  214. }
  215. /* Fill Nodes by nearest center and costs from that center */
  216. G_message(_("Calculating costs from centers ..."));
  217. for (center = 0; center < ncenters; center++) {
  218. G_percent(center, ncenters, 1);
  219. node1 = Centers[center].node;
  220. Vect_net_get_node_cost(&Map, node1, &n1cost);
  221. G_debug(2, "center = %d node = %d cat = %d", center, node1,
  222. Centers[center].cat);
  223. if (turntable_f->answer)
  224. for (line = 1; line <= nlines; line++) {
  225. G_debug(5, " node1 = %d line = %d", node1, line);
  226. Vect_net_get_node_cost(&Map, line, &n2cost);
  227. /* closed, left it as not attached */
  228. if (Vect_read_line(&Map, Points, Cats, line) < 0)
  229. continue;
  230. if (Vect_get_line_type(&Map, line) != GV_LINE)
  231. continue;
  232. if (!Vect_cat_get(Cats, tucfield, &cat))
  233. continue;
  234. for (j = 0; j < 2; j++) {
  235. if (j == 1)
  236. cat *= -1;
  237. ret =
  238. Vect_net_ttb_shortest_path(&Map, node1, 0, cat, 1,
  239. tucfield, NULL,
  240. &cost);
  241. if (ret == -1) {
  242. continue;
  243. } /* node unreachable */
  244. /* We must add center node costs (not calculated by Vect_net_shortest_path() ), but
  245. * only if center and node are not identical, because at the end node cost is add later */
  246. if (ret != 1)
  247. cost += n1cost;
  248. G_debug(5,
  249. "Arc nodes: %d %d cost: %f (x old cent: %d old cost %f",
  250. node1, line, cost, Nodes[line * 2 + j].center,
  251. Nodes[line * 2 + j].cost);
  252. if (Nodes[line * 2 + j].center == -1 ||
  253. cost < Nodes[line * 2 + j].cost) {
  254. Nodes[line * 2 + j].cost = cost;
  255. Nodes[line * 2 + j].center = center;
  256. }
  257. }
  258. }
  259. else
  260. for (node2 = 1; node2 <= nnodes; node2++) {
  261. G_debug(5, " node1 = %d node2 = %d", node1, node2);
  262. Vect_net_get_node_cost(&Map, node2, &n2cost);
  263. if (n2cost == -1) {
  264. continue;
  265. } /* closed, left it as not attached */
  266. ret = Vect_net_shortest_path(&Map, node1, node2, NULL, &cost);
  267. if (ret == -1) {
  268. continue;
  269. } /* node unreachable */
  270. /* We must add center node costs (not calculated by Vect_net_shortest_path() ), but
  271. * only if center and node are not identical, because at the end node cost is add later */
  272. if (node1 != node2)
  273. cost += n1cost;
  274. G_debug(5,
  275. "Arc nodes: %d %d cost: %f (x old cent: %d old cost %f",
  276. node1, node2, cost, Nodes[node2].center,
  277. Nodes[node2].cost);
  278. if (Nodes[node2].center == -1 || cost < Nodes[node2].cost) {
  279. Nodes[node2].cost = cost;
  280. Nodes[node2].center = center;
  281. }
  282. }
  283. }
  284. G_percent(1, 1, 1);
  285. /* Write arcs to new map */
  286. if (Vect_open_new(&Out, output->answer, Vect_is_3d(&Map)) < 0)
  287. G_fatal_error(_("Unable to create vector map <%s>"), output->answer);
  288. Vect_hist_command(&Out);
  289. nlines = Vect_get_num_lines(&Map);
  290. for (line = 1; line <= nlines; line++) {
  291. ltype = Vect_read_line(&Map, Points, NULL, line);
  292. if (!(ltype & type)) {
  293. continue;
  294. }
  295. if (turntable_f->answer) {
  296. center1 = Nodes[line * 2].center;
  297. center2 = Nodes[line * 2 + 1].center;
  298. s1cost = Nodes[line * 2].cost;
  299. s2cost = Nodes[line * 2 + 1].cost;
  300. n1cost = n2cost = 0;
  301. }
  302. else {
  303. Vect_get_line_nodes(&Map, line, &node1, &node2);
  304. center1 = Nodes[node1].center;
  305. center2 = Nodes[node2].center;
  306. s1cost = Nodes[node1].cost;
  307. s2cost = Nodes[node2].cost;
  308. Vect_net_get_node_cost(&Map, node1, &n1cost);
  309. Vect_net_get_node_cost(&Map, node2, &n2cost);
  310. }
  311. Vect_net_get_line_cost(&Map, line, GV_FORWARD, &e1cost);
  312. Vect_net_get_line_cost(&Map, line, GV_BACKWARD, &e2cost);
  313. G_debug(3, "Line %d:", line);
  314. G_debug(3, "Arc centers: %d %d (nodes: %d %d)", center1, center2,
  315. node1, node2);
  316. G_debug(3, " s1cost = %f n1cost = %f e1cost = %f", s1cost, n1cost,
  317. e1cost);
  318. G_debug(3, " s2cost = %f n2cost = %f e2cost = %f", s2cost, n2cost,
  319. e2cost);
  320. Vect_reset_cats(Cats);
  321. /* First check if arc is reachable from at least one side */
  322. if ((center1 != -1 && n1cost != -1 && e1cost != -1) ||
  323. (center2 != -1 && n2cost != -1 && e2cost != -1)) {
  324. /* Line is reachable at least from one side */
  325. G_debug(3, " -> arc is reachable");
  326. if (center1 == center2) { /* both nodes in one area -> whole arc in one area */
  327. if (center1 != -1)
  328. cat = Centers[center1].cat; /* line reachable */
  329. else
  330. cat = Centers[center2].cat;
  331. Vect_cat_set(Cats, 1, cat);
  332. Vect_write_line(&Out, ltype, Points, Cats);
  333. }
  334. else { /* each node in different area */
  335. /* Check if direction is reachable */
  336. if (center1 == -1 || n1cost == -1 || e1cost == -1) { /* closed from first node */
  337. G_debug(3,
  338. " -> arc is not reachable from 1. node -> alloc to 2. node");
  339. cat = Centers[center2].cat;
  340. Vect_cat_set(Cats, 1, cat);
  341. Vect_write_line(&Out, ltype, Points, Cats);
  342. continue;
  343. }
  344. else if (center2 == -1 || n2cost == -1 || e2cost == -1) { /* closed from second node */
  345. G_debug(3,
  346. " -> arc is not reachable from 2. node -> alloc to 1. node");
  347. cat = Centers[center1].cat;
  348. Vect_cat_set(Cats, 1, cat);
  349. Vect_write_line(&Out, ltype, Points, Cats);
  350. continue;
  351. }
  352. /* Now we know that arc is reachable from both sides */
  353. /* Add costs of node to starting costs */
  354. s1cost += n1cost;
  355. s2cost += n2cost;
  356. /* Check if s1cost + e1cost <= s2cost or s2cost + e2cost <= s1cost !
  357. * Note this check also possibility of (e1cost + e2cost) = 0 */
  358. if (s1cost + e1cost <= s2cost) { /* whole arc reachable from node1 */
  359. cat = Centers[center1].cat;
  360. Vect_cat_set(Cats, 1, cat);
  361. Vect_write_line(&Out, ltype, Points, Cats);
  362. }
  363. else if (s2cost + e2cost <= s1cost) { /* whole arc reachable from node2 */
  364. cat = Centers[center2].cat;
  365. Vect_cat_set(Cats, 1, cat);
  366. Vect_write_line(&Out, ltype, Points, Cats);
  367. }
  368. else { /* split */
  369. /* Calculate relative costs - we expect that costs along the line do not change */
  370. l = Vect_line_length(Points);
  371. e1cost /= l;
  372. e2cost /= l;
  373. G_debug(3, " -> s1cost = %f e1cost = %f", s1cost,
  374. e1cost);
  375. G_debug(3, " -> s2cost = %f e2cost = %f", s2cost,
  376. e2cost);
  377. /* Costs from both centers to the splitting point must be equal:
  378. * s1cost + l1 * e1cost = s2cost + l2 * e2cost */
  379. l1 = (l * e2cost - s1cost + s2cost) / (e1cost + e2cost);
  380. l2 = l - l1;
  381. G_debug(3, "l = %f l1 = %f l2 = %f", l, l1, l2);
  382. /* First segment */
  383. ret = Vect_line_segment(Points, 0, l1, SPoints);
  384. if (ret == 0) {
  385. G_warning(_
  386. ("Cannot get line segment, segment out of line"));
  387. }
  388. else {
  389. cat = Centers[center1].cat;
  390. Vect_cat_set(Cats, 1, cat);
  391. Vect_write_line(&Out, ltype, SPoints, Cats);
  392. }
  393. /* Second segment */
  394. ret = Vect_line_segment(Points, l1, l, SPoints);
  395. if (ret == 0) {
  396. G_warning(_
  397. ("Cannot get line segment, segment out of line"));
  398. }
  399. else {
  400. Vect_reset_cats(Cats);
  401. cat = Centers[center2].cat;
  402. Vect_cat_set(Cats, 1, cat);
  403. Vect_write_line(&Out, ltype, SPoints, Cats);
  404. }
  405. }
  406. }
  407. }
  408. else {
  409. /* arc is not reachable */
  410. G_debug(3, " -> arc is not reachable");
  411. Vect_write_line(&Out, ltype, Points, Cats);
  412. }
  413. }
  414. Vect_build(&Out);
  415. /* Free, ... */
  416. G_free(Nodes);
  417. G_free(Centers);
  418. Vect_close(&Map);
  419. Vect_close(&Out);
  420. exit(EXIT_SUCCESS);
  421. }