net_analyze.c 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072
  1. /*!
  2. * \file lib/vector/Vlib/net_analyze.c
  3. *
  4. * \brief Vector library - related fns for vector network analyses
  5. *
  6. * Higher level functions for reading/writing/manipulating vectors.
  7. *
  8. * (C) 2001-2009, 2014 by the GRASS Development Team
  9. *
  10. * This program is free software under the GNU General Public License
  11. * (>=v2). Read the file COPYING that comes with GRASS for details.
  12. *
  13. * \author Radim Blazek
  14. * \author Stepan Turek stepan.turek seznam.cz (turns support)
  15. */
  16. #include <grass/dbmi.h>
  17. #include <grass/vector.h>
  18. #include <grass/glocale.h>
  19. static int From_node; /* from node set in SP and used by clipper for first arc */
  20. static int clipper(dglGraph_s * pgraph,
  21. dglSPClipInput_s * pargIn,
  22. dglSPClipOutput_s * pargOut, void *pvarg)
  23. { /* caller's pointer */
  24. dglInt32_t cost;
  25. dglInt32_t from;
  26. G_debug(3, "Net: clipper()");
  27. from = dglNodeGet_Id(pgraph, pargIn->pnNodeFrom);
  28. G_debug(3, " Edge = %d NodeFrom = %d NodeTo = %d edge cost = %d",
  29. (int)dglEdgeGet_Id(pgraph, pargIn->pnEdge),
  30. (int)from, (int)dglNodeGet_Id(pgraph, pargIn->pnNodeTo),
  31. (int)pargOut->nEdgeCost);
  32. if (from != From_node) { /* do not clip first */
  33. if (dglGet_NodeAttrSize(pgraph) > 0) {
  34. memcpy(&cost, dglNodeGet_Attr(pgraph, pargIn->pnNodeFrom),
  35. sizeof(cost));
  36. if (cost == -1) { /* closed, cannot go from this node except it is 'from' node */
  37. G_debug(3, " closed node");
  38. return 1;
  39. }
  40. else {
  41. G_debug(3, " EdgeCost += %d (node)", (int)cost);
  42. pargOut->nEdgeCost += cost;
  43. }
  44. }
  45. }
  46. else {
  47. G_debug(3, " don't clip first node");
  48. }
  49. return 0;
  50. }
  51. /*!
  52. \brief Converts shortest path result, which is calculated by DGLib on newtwork without turntable, into output format.
  53. */
  54. static int convert_dgl_shortest_path_result(struct Map_info *Map,
  55. dglSPReport_s * pSPReport,
  56. struct ilist *List)
  57. {
  58. int i, line;
  59. Vect_reset_list(List);
  60. for (i = 0; i < pSPReport->cArc; i++) {
  61. line =
  62. dglEdgeGet_Id(&(Map->dgraph.graph_s), pSPReport->pArc[i].pnEdge);
  63. G_debug(2, "From %ld to %ld - cost %ld user %d distance %ld", pSPReport->pArc[i].nFrom, pSPReport->pArc[i].nTo, dglEdgeGet_Cost(&(Map->dgraph.graph_s), pSPReport->pArc[i].pnEdge) / Map->dgraph.cost_multip, /* this is the cost from clip() */
  64. line, pSPReport->pArc[i].nDistance);
  65. Vect_list_append(List, line);
  66. }
  67. return 0;
  68. }
  69. /*!
  70. \brief Converts shortest path result, which is calculated by DGLib on newtwork with turntable, into output format.
  71. */
  72. static int ttb_convert_dgl_shortest_path_result(struct Map_info *Map,
  73. dglSPReport_s * pSPReport,
  74. int tucfield,
  75. struct ilist *List)
  76. {
  77. int i, line_id, type, tucfield_idx;
  78. int line_ucat;
  79. Vect_reset_list(List);
  80. tucfield_idx = Vect_cidx_get_field_index(Map, tucfield);
  81. for (i = 0; i < pSPReport->cArc; i++) {
  82. dglEdgeGet_Id(&(Map->dgraph.graph_s), pSPReport->pArc[i].pnEdge);
  83. line_ucat =
  84. dglNodeGet_Id(&(Map->dgraph.graph_s),
  85. dglEdgeGet_Head(&(Map->dgraph.graph_s),
  86. pSPReport->pArc[i].pnEdge));
  87. /* get standard ucat numbers (DGLib does not like negative node numbers) */
  88. if (line_ucat % 2 == 1)
  89. line_ucat = ((line_ucat - 1) / -2);
  90. else
  91. line_ucat = (line_ucat) / 2;
  92. /* skip virtual nodes */
  93. if (Vect_cidx_find_next
  94. (Map, tucfield_idx, abs(line_ucat), GV_LINE, 0, &type,
  95. &line_id) == -1)
  96. continue;
  97. if (line_ucat < 0)
  98. line_id *= -1;
  99. G_debug(2, "From %ld to %ld - cost %ld user %d distance %ld", pSPReport->pArc[i].nFrom, pSPReport->pArc[i].nTo, dglEdgeGet_Cost(&(Map->dgraph.graph_s), pSPReport->pArc[i].pnEdge) / Map->dgraph.cost_multip, /* this is the cost from clip() */
  100. line_ucat, pSPReport->pArc[i].nDistance);
  101. Vect_list_append(List, line_id);
  102. }
  103. return 0;
  104. }
  105. /*!
  106. \brief Finds shortest path on network using DGLib
  107. \param Map vector map with build DGLib graph (see Vect_net_ttb_build_graph and Vect_net_build_graph)
  108. \param from from node id in build the network
  109. \param to to node in build the network
  110. \param UseTtb the graph is build with/without turntable
  111. \param tucfield layer with unique cats for turntable (relevant only when UseTtb = 1)
  112. */
  113. static int find_shortest_path(struct Map_info *Map, int from, int to,
  114. struct ilist *List, double *cost, int UseTtb,
  115. int tucfield)
  116. {
  117. int *pclip, cArc, nRet;
  118. dglSPReport_s *pSPReport;
  119. dglInt32_t nDistance;
  120. int use_cache = 1; /* set to 0 to disable dglib cache */
  121. G_debug(3, "find_shortest_path(): from = %d, to = %d", from, to);
  122. /* Note : if from == to dgl goes to nearest node and returns back (dgl feature) =>
  123. * check here for from == to */
  124. if (List != NULL)
  125. Vect_reset_list(List);
  126. /* Check if from and to are identical, otherwise dglib returns path to neares node and back! */
  127. if (from == to) {
  128. if (cost != NULL)
  129. *cost = 0;
  130. return 0;
  131. }
  132. From_node = from;
  133. pclip = NULL;
  134. if (List != NULL) {
  135. if (use_cache) {
  136. nRet =
  137. dglShortestPath(&(Map->dgraph.graph_s), &pSPReport,
  138. (dglInt32_t) from, (dglInt32_t) to, clipper,
  139. pclip, &(Map->dgraph.spCache));
  140. }
  141. else {
  142. nRet =
  143. dglShortestPath(&(Map->dgraph.graph_s), &pSPReport,
  144. (dglInt32_t) from, (dglInt32_t) to, clipper,
  145. pclip, NULL);
  146. }
  147. }
  148. else {
  149. if (use_cache) {
  150. nRet =
  151. dglShortestDistance(&(Map->dgraph.graph_s), &nDistance,
  152. (dglInt32_t) from, (dglInt32_t) to,
  153. clipper, pclip, &(Map->dgraph.spCache));
  154. }
  155. else {
  156. nRet =
  157. dglShortestDistance(&(Map->dgraph.graph_s), &nDistance,
  158. (dglInt32_t) from, (dglInt32_t) to,
  159. clipper, pclip, NULL);
  160. }
  161. }
  162. if (nRet == 0) {
  163. /* G_warning("Destination node %d is unreachable from node %d\n" , to , from); */
  164. if (cost != NULL)
  165. *cost = PORT_DOUBLE_MAX;
  166. return -1;
  167. }
  168. else if (nRet < 0) {
  169. G_warning(_("dglShortestPath error: %s"),
  170. dglStrerror(&(Map->dgraph.graph_s)));
  171. return -1;
  172. }
  173. if (List != NULL) {
  174. if (UseTtb)
  175. ttb_convert_dgl_shortest_path_result(Map, pSPReport, tucfield,
  176. List);
  177. else
  178. convert_dgl_shortest_path_result(Map, pSPReport, List);
  179. }
  180. if (cost != NULL) {
  181. if (List != NULL)
  182. *cost = (double)pSPReport->nDistance / Map->dgraph.cost_multip;
  183. else
  184. *cost = (double)nDistance / Map->dgraph.cost_multip;
  185. }
  186. if (List != NULL) {
  187. cArc = pSPReport->cArc;
  188. dglFreeSPReport(&(Map->dgraph.graph_s), pSPReport);
  189. }
  190. else
  191. cArc = 0;
  192. return cArc;
  193. }
  194. /*!
  195. \brief Find shortest path on network.
  196. Costs for 'from' and 'to' nodes are not considered (SP found even if
  197. 'from' or 'to' are 'closed' (costs = -1) and costs of these
  198. nodes are not added to SP costs result.
  199. \param Map vector map with build graph (see Vect_net_ttb_build_graph and Vect_net_build_graph)
  200. \param from start of the path
  201. \param from_type if 0 - node id (intersection), if 1 - line unique cat
  202. \param to end of the path
  203. \param to_type if 0 - node id (intersection), if 1 - line unique cat
  204. \param tucfield field with unique categories used in the turntable
  205. \param[out] List list of line ids (path)
  206. \param[out] cost costs value
  207. \return number of segments
  208. \return 0 is correct for from = to, or List == NULL ? sum of costs is better return value,
  209. \return -1 : destination unreachable
  210. */
  211. int
  212. Vect_net_ttb_shortest_path(struct Map_info *Map, int from, int from_type,
  213. int to, int to_type,
  214. int tucfield, struct ilist *List, double *cost)
  215. {
  216. double x, y, z;
  217. struct bound_box box;
  218. struct boxlist *box_List;
  219. struct line_cats *Cats;
  220. int f, t;
  221. int i_line, line, type, cfound;
  222. box_List = Vect_new_boxlist(0);
  223. Cats = Vect_new_cats_struct();
  224. if (from_type == 0) { /* TODO duplicite code with to_type, move into function */
  225. /* select points at node */
  226. Vect_get_node_coor(Map, from, &x, &y, &z);
  227. box.E = box.W = x;
  228. box.N = box.S = y;
  229. box.T = box.B = z;
  230. Vect_select_lines_by_box(Map, &box, GV_POINT, box_List);
  231. cfound = 0;
  232. for (i_line = 0; i_line < box_List->n_values; i_line++) {
  233. line = box_List->id[i_line];
  234. type = Vect_read_line(Map, NULL, Cats, line);
  235. if (!(type & GV_POINT))
  236. continue;
  237. if (Vect_cat_get(Cats, tucfield, &f)) {
  238. ++cfound;
  239. break;
  240. }
  241. }
  242. if (!cfound)
  243. G_fatal_error(_
  244. ("Unable to find point with defined unique category for node <%d>."),
  245. from);
  246. else if (cfound > 1)
  247. G_warning(_
  248. ("There exists more than one point on node <%d> with unique category in field <%d>.\n"
  249. "The unique category layer may not be valid."),
  250. tucfield, from);
  251. G_debug(2, "from node = %d, unique cat = %d ", from, f);
  252. f = f * 2;
  253. }
  254. else {
  255. if (from < 0)
  256. f = from * -2 + 1;
  257. else
  258. f = from * 2;
  259. G_debug(2, "from edge unique cat = %d", from);
  260. }
  261. if (to_type == 0) {
  262. /* select points at node */
  263. Vect_get_node_coor(Map, to, &x, &y, &z);
  264. box.E = box.W = x;
  265. box.N = box.S = y;
  266. box.T = box.B = z;
  267. Vect_select_lines_by_box(Map, &box, GV_POINT, box_List);
  268. cfound = 0;
  269. for (i_line = 0; i_line < box_List->n_values; i_line++) {
  270. line = box_List->id[i_line];
  271. type = Vect_read_line(Map, NULL, Cats, line);
  272. if (!(type & GV_POINT))
  273. continue;
  274. if (Vect_cat_get(Cats, tucfield, &t)) {
  275. cfound = 1;
  276. break;
  277. }
  278. }
  279. if (!cfound)
  280. G_fatal_error(_
  281. ("Unable to find point with defined unique category for node <%d>."),
  282. to);
  283. else if (cfound > 1)
  284. G_warning(_
  285. ("There exists more than one point on node <%d> with unique category in field <%d>.\n"
  286. "The unique category layer may not be valid."),
  287. tucfield, to);
  288. G_debug(2, "to node = %d, unique cat = %d ", to, t);
  289. t = t * 2 + 1;
  290. }
  291. else {
  292. if (to < 0)
  293. t = to * -2 + 1;
  294. else
  295. t = to * 2;
  296. G_debug(2, "to edge unique cat = %d", to);
  297. }
  298. Vect_destroy_boxlist(box_List);
  299. Vect_destroy_cats_struct(Cats);
  300. return find_shortest_path(Map, f, t, List, cost, 1, tucfield);
  301. }
  302. /*!
  303. \brief Find shortest path.
  304. Costs for 'from' and 'to' nodes are not considered (SP found even if
  305. 'from' or 'to' are 'closed' (costs = -1) and costs of these
  306. nodes are not added to SP costs result.
  307. \param Map vector map with build graph (see Vect_net_ttb_build_graph and Vect_net_build_graph)
  308. \param from from node
  309. \param to to node
  310. \param[out] List list of line ids (path)
  311. \param[out] cost costs value
  312. \return number of segments
  313. \return 0 is correct for from = to, or List == NULL ? sum of costs is better return value,
  314. \return -1 : destination unreachable
  315. */
  316. int
  317. Vect_net_shortest_path(struct Map_info *Map, int from, int to,
  318. struct ilist *List, double *cost)
  319. {
  320. return find_shortest_path(Map, from, to, List, cost, 0, -1);
  321. }
  322. /*!
  323. \brief Get graph structure
  324. Graph is built by Vect_net_build_graph().
  325. Returns NULL when graph is not built.
  326. \param Map pointer to Map_info struct
  327. \return pointer to dglGraph_s struct or NULL
  328. */
  329. dglGraph_s *Vect_net_get_graph(struct Map_info * Map)
  330. {
  331. return &(Map->dgraph.graph_s);
  332. }
  333. /*!
  334. \brief Returns in cost for given direction in *cost.
  335. cost is set to -1 if closed.
  336. \param Map vector map with build graph (see Vect_net_ttb_build_graph and Vect_net_build_graph)
  337. \param line line id
  338. \param direction direction (GV_FORWARD, GV_BACKWARD)
  339. \param[out] cost
  340. \return 1 OK
  341. \return 0 does not exist (was not inserted)
  342. */
  343. int
  344. Vect_net_get_line_cost(const struct Map_info *Map, int line, int direction,
  345. double *cost)
  346. {
  347. /* dglInt32_t *pEdge; */
  348. G_debug(5, "Vect_net_get_line_cost(): line = %d, dir = %d", line,
  349. direction);
  350. if (direction == GV_FORWARD) {
  351. /* V1 has no index by line-id -> array used */
  352. /*
  353. pEdge = dglGetEdge(&(Map->dgraph.graph_s), line);
  354. if (pEdge == NULL)
  355. return 0;
  356. *cost = (double) dglEdgeGet_Cost(&(Map->dgraph.graph_s), pEdge);
  357. */
  358. if (Map->dgraph.edge_fcosts[line] == -1) {
  359. *cost = -1;
  360. return 0;
  361. }
  362. else
  363. *cost = Map->dgraph.edge_fcosts[line];
  364. }
  365. else if (direction == GV_BACKWARD) {
  366. /*
  367. pEdge = dglGetEdge(&(Map->dgraph.graph_s), -line);
  368. if (pEdge == NULL)
  369. return 0;
  370. *cost = (double) dglEdgeGet_Cost(&(Map->dgraph.graph_s), pEdge);
  371. */
  372. if (Map->dgraph.edge_bcosts[line] == -1) {
  373. *cost = -1;
  374. return 0;
  375. }
  376. else
  377. *cost = Map->dgraph.edge_bcosts[line];
  378. G_debug(5, "Vect_net_get_line_cost(): edge_bcosts = %f",
  379. Map->dgraph.edge_bcosts[line]);
  380. }
  381. else {
  382. G_fatal_error(_("Wrong line direction in Vect_net_get_line_cost()"));
  383. }
  384. return 1;
  385. }
  386. /*!
  387. \brief Get cost of node
  388. \param Map vector map with build graph (see Vect_net_ttb_build_graph and Vect_net_build_graph)
  389. \param node node id
  390. \param[out] cost costs value
  391. \return 1
  392. */
  393. int Vect_net_get_node_cost(const struct Map_info *Map, int node, double *cost)
  394. {
  395. G_debug(3, "Vect_net_get_node_cost(): node = %d", node);
  396. *cost = Map->dgraph.node_costs[node];
  397. G_debug(3, " -> cost = %f", *cost);
  398. return 1;
  399. }
  400. /*!
  401. \brief Find nearest node(s) on network.
  402. \param Map vector map with build graph (see Vect_net_ttb_build_graph and Vect_net_build_graph)
  403. \param x,y,z point coordinates (z coordinate NOT USED !)
  404. \param direction (GV_FORWARD - from point to net, GV_BACKWARD - from net to point)
  405. \param maxdist maximum distance to the network
  406. \param[out] node1 pointer where to store the node number (or NULL)
  407. \param[out] node2 pointer where to store the node number (or NULL)
  408. \param[out] ln pointer where to store the nearest line number (or NULL)
  409. \param[out] costs1 pointer where to store costs on nearest line to node1 (not costs from x,y,z to the line) (or NULL)
  410. \param[out] costs2 pointer where to store costs on nearest line to node2 (not costs from x,y,z to the line) (or NULL)
  411. \param[out] Points1 pointer to structure where to store vertices on nearest line to node1 (or NULL)
  412. \param[out] Points2 pointer to structure where to store vertices on nearest line to node2 (or NULL)
  413. \param[out] pointer where to distance to the line (or NULL)
  414. \param[out] distance
  415. \return number of nodes found (0,1,2)
  416. */
  417. int Vect_net_nearest_nodes(struct Map_info *Map,
  418. double x, double y, double z,
  419. int direction, double maxdist,
  420. int *node1, int *node2, int *ln, double *costs1,
  421. double *costs2, struct line_pnts *Points1,
  422. struct line_pnts *Points2, double *distance)
  423. {
  424. int line, n1, n2, nnodes;
  425. int npoints;
  426. int segment; /* nearest line segment (first is 1) */
  427. static struct line_pnts *Points = NULL;
  428. double cx, cy, cz, c1, c2;
  429. double along; /* distance along the line to nearest point */
  430. double length;
  431. G_debug(3, "Vect_net_nearest_nodes() x = %f y = %f", x, y);
  432. /* Reset */
  433. if (node1)
  434. *node1 = 0;
  435. if (node2)
  436. *node2 = 0;
  437. if (ln)
  438. *ln = 0;
  439. if (costs1)
  440. *costs1 = PORT_DOUBLE_MAX;
  441. if (costs2)
  442. *costs2 = PORT_DOUBLE_MAX;
  443. if (Points1)
  444. Vect_reset_line(Points1);
  445. if (Points2)
  446. Vect_reset_line(Points2);
  447. if (distance)
  448. *distance = PORT_DOUBLE_MAX;
  449. if (!Points)
  450. Points = Vect_new_line_struct();
  451. /* Find nearest line */
  452. line = Vect_find_line(Map, x, y, z, Map->dgraph.line_type, maxdist, 0, 0);
  453. if (line < 1)
  454. return 0;
  455. Vect_read_line(Map, Points, NULL, line);
  456. npoints = Points->n_points;
  457. Vect_get_line_nodes(Map, line, &n1, &n2);
  458. segment =
  459. Vect_line_distance(Points, x, y, z, 0, &cx, &cy, &cz, distance, NULL,
  460. &along);
  461. G_debug(4, "line = %d n1 = %d n2 = %d segment = %d", line, n1, n2,
  462. segment);
  463. /* Check first or last point and return one node in that case */
  464. G_debug(4, "cx = %f cy = %f first = %f %f last = %f %f", cx, cy,
  465. Points->x[0], Points->y[0], Points->x[npoints - 1],
  466. Points->y[npoints - 1]);
  467. if (Points->x[0] == cx && Points->y[0] == cy) {
  468. if (node1)
  469. *node1 = n1;
  470. if (ln)
  471. *ln = line;
  472. if (costs1)
  473. *costs1 = 0;
  474. if (Points1) {
  475. Vect_append_point(Points1, x, y, z);
  476. Vect_append_point(Points1, cx, cy, cz);
  477. }
  478. G_debug(3, "first node nearest");
  479. return 1;
  480. }
  481. if (Points->x[npoints - 1] == cx && Points->y[npoints - 1] == cy) {
  482. if (node1)
  483. *node1 = n2;
  484. if (ln)
  485. *ln = line;
  486. if (costs1)
  487. *costs1 = 0;
  488. if (Points1) {
  489. Vect_append_point(Points1, x, y, z);
  490. Vect_append_point(Points1, cx, cy, cz);
  491. }
  492. G_debug(3, "last node nearest");
  493. return 1;
  494. }
  495. nnodes = 2;
  496. /* c1 - costs to get from/to the first vertex */
  497. /* c2 - costs to get from/to the last vertex */
  498. if (direction == GV_FORWARD) { /* from point to net */
  499. Vect_net_get_line_cost(Map, line, GV_BACKWARD, &c1);
  500. Vect_net_get_line_cost(Map, line, GV_FORWARD, &c2);
  501. }
  502. else {
  503. Vect_net_get_line_cost(Map, line, GV_FORWARD, &c1);
  504. Vect_net_get_line_cost(Map, line, GV_BACKWARD, &c2);
  505. }
  506. if (c1 < 0)
  507. nnodes--;
  508. if (c2 < 0)
  509. nnodes--;
  510. if (nnodes == 0)
  511. return 0; /* both directions closed */
  512. length = Vect_line_length(Points);
  513. if (ln)
  514. *ln = line;
  515. if (nnodes == 1 && c1 < 0) { /* first direction is closed, return node2 as node1 */
  516. if (node1)
  517. *node1 = n2;
  518. if (costs1) { /* to node 2, i.e. forward */
  519. *costs1 = c2 * (length - along) / length;
  520. }
  521. if (Points1) { /* to node 2, i.e. forward */
  522. int i;
  523. if (direction == GV_FORWARD) { /* from point to net */
  524. Vect_append_point(Points1, x, y, z);
  525. Vect_append_point(Points1, cx, cy, cz);
  526. for (i = segment; i < npoints; i++)
  527. Vect_append_point(Points1, Points->x[i], Points->y[i],
  528. Points->z[i]);
  529. }
  530. else {
  531. for (i = npoints - 1; i >= segment; i--)
  532. Vect_append_point(Points1, Points->x[i], Points->y[i],
  533. Points->z[i]);
  534. Vect_append_point(Points1, cx, cy, cz);
  535. Vect_append_point(Points1, x, y, z);
  536. }
  537. }
  538. }
  539. else {
  540. if (node1)
  541. *node1 = n1;
  542. if (node2)
  543. *node2 = n2;
  544. if (costs1) { /* to node 1, i.e. backward */
  545. *costs1 = c1 * along / length;
  546. }
  547. if (costs2) { /* to node 2, i.e. forward */
  548. *costs2 = c2 * (length - along) / length;
  549. }
  550. if (Points1) { /* to node 1, i.e. backward */
  551. int i;
  552. if (direction == GV_FORWARD) { /* from point to net */
  553. Vect_append_point(Points1, x, y, z);
  554. Vect_append_point(Points1, cx, cy, cz);
  555. for (i = segment - 1; i >= 0; i--)
  556. Vect_append_point(Points1, Points->x[i], Points->y[i],
  557. Points->z[i]);
  558. }
  559. else {
  560. for (i = 0; i < segment; i++)
  561. Vect_append_point(Points1, Points->x[i], Points->y[i],
  562. Points->z[i]);
  563. Vect_append_point(Points1, cx, cy, cz);
  564. Vect_append_point(Points1, x, y, z);
  565. }
  566. }
  567. if (Points2) { /* to node 2, i.e. forward */
  568. int i;
  569. if (direction == GV_FORWARD) { /* from point to net */
  570. Vect_append_point(Points2, x, y, z);
  571. Vect_append_point(Points2, cx, cy, cz);
  572. for (i = segment; i < npoints; i++)
  573. Vect_append_point(Points2, Points->x[i], Points->y[i],
  574. Points->z[i]);
  575. }
  576. else {
  577. for (i = npoints - 1; i >= segment; i--)
  578. Vect_append_point(Points2, Points->x[i], Points->y[i],
  579. Points->z[i]);
  580. Vect_append_point(Points2, cx, cy, cz);
  581. Vect_append_point(Points2, x, y, z);
  582. }
  583. }
  584. }
  585. return nnodes;
  586. }
  587. /*!
  588. \brief Find shortest path on network between 2 points given by coordinates.
  589. \param Map vector map with build graph (see Vect_net_ttb_build_graph and Vect_net_build_graph)
  590. \param fx,fy,fz from point x coordinate (z ignored)
  591. \param tx,ty,tz to point x coordinate (z ignored)
  592. \param fmax maximum distance to the network from 'from'
  593. \param tmax maximum distance to the network from 'to'
  594. \param UseTtb the graph is build with/without turntable
  595. \param tucfield field with unique categories used in the turntable
  596. \param costs pointer where to store costs on the network (or NULL)
  597. \param Points pointer to the structure where to store vertices of shortest path (or NULL)
  598. \param List pointer to the structure where list of lines on the network is stored (or NULL)
  599. \param NodesList pointer to the structure where list of nodes on the network is stored (or NULL)
  600. \param FPoints pointer to the structure where to store line from 'from' to first network node (or NULL)
  601. \param TPoints pointer to the structure where to store line from last network node to 'to' (or NULL)
  602. \param fdist distance from 'from' to the net (or NULL)
  603. \param tdist distance from 'to' to the net (or NULL)
  604. \return 1 OK, 0 not reachable
  605. */
  606. static int
  607. find_shortest_path_coor(struct Map_info *Map,
  608. double fx, double fy, double fz, double tx,
  609. double ty, double tz, double fmax, double tmax,
  610. int UseTtb, int tucfield,
  611. double *costs, struct line_pnts *Points,
  612. struct ilist *List, struct ilist *NodesList,
  613. struct line_pnts *FPoints,
  614. struct line_pnts *TPoints, double *fdist,
  615. double *tdist)
  616. {
  617. int fnode[2], tnode[2]; /* nearest nodes, *node[1] is 0 if only one was found */
  618. double fcosts[2], tcosts[2], cur_cst; /* costs to nearest nodes on the network */
  619. int nfnodes, ntnodes, fline, tline;
  620. static struct line_pnts *APoints, *SPoints, *fPoints[2], *tPoints[2];
  621. static struct ilist *LList;
  622. static int first = 1;
  623. int reachable, shortcut;
  624. int i, j, fn = 0, tn = 0;
  625. /* from/to_point_node is set if from/to point projected to line
  626. *falls exactly on node (shortcut -> fline == tline) */
  627. int from_point_node = 0;
  628. int to_point_node = 0;
  629. G_debug(3, "Vect_net_shortest_path_coor()");
  630. if (first) {
  631. APoints = Vect_new_line_struct();
  632. SPoints = Vect_new_line_struct();
  633. fPoints[0] = Vect_new_line_struct();
  634. fPoints[1] = Vect_new_line_struct();
  635. tPoints[0] = Vect_new_line_struct();
  636. tPoints[1] = Vect_new_line_struct();
  637. LList = Vect_new_list();
  638. first = 0;
  639. }
  640. /* Reset */
  641. if (costs)
  642. *costs = PORT_DOUBLE_MAX;
  643. if (Points)
  644. Vect_reset_line(Points);
  645. if (fdist)
  646. *fdist = 0;
  647. if (tdist)
  648. *tdist = 0;
  649. if (List)
  650. List->n_values = 0;
  651. if (FPoints)
  652. Vect_reset_line(FPoints);
  653. if (TPoints)
  654. Vect_reset_line(TPoints);
  655. if (NodesList != NULL)
  656. Vect_reset_list(NodesList);
  657. /* Find nearest nodes */
  658. fnode[0] = fnode[1] = tnode[0] = tnode[1] = 0;
  659. nfnodes =
  660. Vect_net_nearest_nodes(Map, fx, fy, fz, GV_FORWARD, fmax, &(fnode[0]),
  661. &(fnode[1]), &fline, &(fcosts[0]),
  662. &(fcosts[1]), fPoints[0], fPoints[1], fdist);
  663. if (nfnodes == 0)
  664. return 0;
  665. if (nfnodes == 1 && fPoints[0]->n_points < 3) {
  666. from_point_node = fnode[0];
  667. }
  668. ntnodes =
  669. Vect_net_nearest_nodes(Map, tx, ty, tz, GV_BACKWARD, tmax,
  670. &(tnode[0]), &(tnode[1]), &tline, &(tcosts[0]),
  671. &(tcosts[1]), tPoints[0], tPoints[1], tdist);
  672. if (ntnodes == 0)
  673. return 0;
  674. if (ntnodes == 1 && tPoints[0]->n_points < 3) {
  675. to_point_node = tnode[0];
  676. }
  677. G_debug(3, "fline = %d tline = %d", fline, tline);
  678. reachable = shortcut = 0;
  679. cur_cst = PORT_DOUBLE_MAX;
  680. /* It may happen, that 2 points are at the same line. */
  681. /* TODO?: it could also happen that fline != tline but both points are on the same
  682. * line if they fall on node but a different line was found. This case is correctly
  683. * handled as normal non shortcut, but it could be added here. In that case
  684. * NodesList collection must be changed */
  685. if (fline == tline && (nfnodes > 1 || ntnodes > 1)) {
  686. double len, flen, tlen, c, fseg, tseg;
  687. double fcx, fcy, fcz, tcx, tcy, tcz;
  688. Vect_read_line(Map, APoints, NULL, fline);
  689. len = Vect_line_length(APoints);
  690. /* distance along the line */
  691. fseg =
  692. Vect_line_distance(APoints, fx, fy, fz, 0, &fcx, &fcy, &fcz, NULL,
  693. NULL, &flen);
  694. tseg =
  695. Vect_line_distance(APoints, tx, ty, tz, 0, &tcx, &tcy, &tcz, NULL,
  696. NULL, &tlen);
  697. Vect_reset_line(SPoints);
  698. if (flen == tlen) {
  699. cur_cst = 0;
  700. Vect_append_point(SPoints, fx, fy, fz);
  701. Vect_append_point(SPoints, fcx, fcy, fcz);
  702. Vect_append_point(SPoints, tx, ty, tz);
  703. reachable = shortcut = 1;
  704. }
  705. else if (flen < tlen) {
  706. Vect_net_get_line_cost(Map, fline, GV_FORWARD, &c);
  707. if (c >= 0) {
  708. cur_cst = c * (tlen - flen) / len;
  709. Vect_append_point(SPoints, fx, fy, fz);
  710. Vect_append_point(SPoints, fcx, fcy, fcz);
  711. for (i = fseg; i < tseg; i++)
  712. Vect_append_point(SPoints, APoints->x[i], APoints->y[i],
  713. APoints->z[i]);
  714. Vect_append_point(SPoints, tcx, tcy, tcz);
  715. Vect_append_point(SPoints, tx, ty, tz);
  716. reachable = shortcut = 1;
  717. }
  718. }
  719. else { /* flen > tlen */
  720. Vect_net_get_line_cost(Map, fline, GV_BACKWARD, &c);
  721. if (c >= 0) {
  722. cur_cst = c * (flen - tlen) / len;
  723. Vect_append_point(SPoints, fx, fy, fz);
  724. Vect_append_point(SPoints, fcx, fcy, fcz);
  725. for (i = fseg - 1; i >= tseg; i--)
  726. Vect_append_point(SPoints, APoints->x[i], APoints->y[i],
  727. APoints->z[i]);
  728. Vect_append_point(SPoints, tcx, tcy, tcz);
  729. Vect_append_point(SPoints, tx, ty, tz);
  730. reachable = shortcut = 1;
  731. }
  732. }
  733. }
  734. /* Find the shortest variant from maximum 4 */
  735. for (i = 0; i < nfnodes; i++) {
  736. for (j = 0; j < ntnodes; j++) {
  737. double ncst, cst;
  738. int ret;
  739. G_debug(3, "i = %d fnode = %d j = %d tnode = %d", i, fnode[i], j,
  740. tnode[j]);
  741. if (UseTtb)
  742. ret =
  743. Vect_net_ttb_shortest_path(Map, fnode[i], 0, tnode[j], 0,
  744. tucfield, NULL, &ncst);
  745. else
  746. ret =
  747. Vect_net_shortest_path(Map, fnode[i], tnode[j], NULL,
  748. &ncst);
  749. if (ret == -1)
  750. continue; /* not reachable */
  751. cst = fcosts[i] + ncst + tcosts[j];
  752. if (reachable == 0 || cst < cur_cst) {
  753. cur_cst = cst;
  754. fn = i;
  755. tn = j;
  756. shortcut = 0;
  757. }
  758. reachable = 1;
  759. }
  760. }
  761. G_debug(3, "reachable = %d shortcut = %d cur_cst = %f", reachable,
  762. shortcut, cur_cst);
  763. if (reachable) {
  764. if (shortcut) {
  765. if (Points)
  766. Vect_append_points(Points, SPoints, GV_FORWARD);
  767. if (NodesList) {
  768. /* Check if from/to point projected to line falls on node and
  769. *add it to the list */
  770. if (from_point_node > 0)
  771. Vect_list_append(NodesList, from_point_node);
  772. if (to_point_node > 0)
  773. Vect_list_append(NodesList, to_point_node);
  774. }
  775. }
  776. else {
  777. if (NodesList) {
  778. /* it can happen that starting point falls on node but SP starts
  779. * form the other node, add it in that case,
  780. * similarly for to point below */
  781. if (from_point_node > 0 && from_point_node != fnode[fn]) {
  782. Vect_list_append(NodesList, from_point_node);
  783. }
  784. /* add starting net SP search node */
  785. Vect_list_append(NodesList, fnode[fn]);
  786. }
  787. if (UseTtb)
  788. Vect_net_ttb_shortest_path(Map, fnode[fn], 0, tnode[tn], 0,
  789. tucfield, LList, NULL);
  790. else
  791. Vect_net_shortest_path(Map, fnode[fn], tnode[tn], LList,
  792. NULL);
  793. G_debug(3, "Number of lines %d", LList->n_values);
  794. if (Points)
  795. Vect_append_points(Points, fPoints[fn], GV_FORWARD);
  796. if (FPoints)
  797. Vect_append_points(FPoints, fPoints[fn], GV_FORWARD);
  798. for (i = 0; i < LList->n_values; i++) {
  799. int line;
  800. line = LList->value[i];
  801. G_debug(3, "i = %d line = %d", i, line);
  802. if (Points) {
  803. Vect_read_line(Map, APoints, NULL, abs(line));
  804. if (line > 0)
  805. Vect_append_points(Points, APoints, GV_FORWARD);
  806. else
  807. Vect_append_points(Points, APoints, GV_BACKWARD);
  808. Points->n_points--;
  809. }
  810. if (NodesList) {
  811. int node, node1, node2;
  812. Vect_get_line_nodes(Map, abs(line), &node1, &node2);
  813. /* add the second node, the first of first segmet was alread added */
  814. if (line > 0)
  815. node = node2;
  816. else
  817. node = node1;
  818. Vect_list_append(NodesList, node);
  819. }
  820. if (List)
  821. Vect_list_append(List, line);
  822. }
  823. if (Points) {
  824. if (LList->n_values)
  825. Points->n_points++;
  826. Vect_append_points(Points, tPoints[tn], GV_FORWARD);
  827. }
  828. if (TPoints)
  829. Vect_append_points(TPoints, tPoints[tn], GV_FORWARD);
  830. if (NodesList) {
  831. if (to_point_node > 0 && to_point_node != tnode[tn]) {
  832. Vect_list_append(NodesList, to_point_node);
  833. }
  834. }
  835. }
  836. if (costs)
  837. *costs = cur_cst;
  838. if (Points)
  839. Vect_line_prune(Points);
  840. }
  841. return reachable;
  842. }
  843. /*!
  844. \brief Find shortest path on network between 2 points given by coordinates.
  845. \param Map vector map with build graph (see Vect_net_ttb_build_graph and Vect_net_build_graph)
  846. \param fx,fy,fz from point x coordinate (z ignored)
  847. \param tx,ty,tz to point x coordinate (z ignored)
  848. \param fmax maximum distance to the network from 'from'
  849. \param tmax maximum distance to the network from 'to'
  850. \param costs pointer where to store costs on the network (or NULL)
  851. \param Points pointer to the structure where to store vertices of shortest path (or NULL)
  852. \param List pointer to the structure where list of lines on the network is stored (or NULL)
  853. \param NodesList pointer to the structure where list of nodes on the network is stored (or NULL)
  854. \param FPoints pointer to the structure where to store line from 'from' to first network node (or NULL)
  855. \param TPoints pointer to the structure where to store line from last network node to 'to' (or NULL)
  856. \param fdist distance from 'from' to the net (or NULL)
  857. \param tdist distance from 'to' to the net (or NULL)
  858. \return 1 OK, 0 not reachable
  859. */
  860. int
  861. Vect_net_shortest_path_coor(struct Map_info *Map,
  862. double fx, double fy, double fz, double tx,
  863. double ty, double tz, double fmax, double tmax,
  864. double *costs, struct line_pnts *Points,
  865. struct ilist *List, struct ilist *NodesList,
  866. struct line_pnts *FPoints,
  867. struct line_pnts *TPoints, double *fdist,
  868. double *tdist)
  869. {
  870. return find_shortest_path_coor(Map, fx, fy, fz, tx, ty, tz, fmax, tmax, 0,
  871. 0, costs, Points, List, NodesList,
  872. FPoints, TPoints, fdist, tdist);
  873. }
  874. /*!
  875. \brief Find shortest path on network with turntable between 2 points given by coordinates.
  876. \param Map vector map with build graph (see Vect_net_ttb_build_graph and Vect_net_build_graph)
  877. \param fx,fy,fz from point x coordinate (z ignored)
  878. \param tx,ty,tz to point x coordinate (z ignored)
  879. \param fmax maximum distance to the network from 'from'
  880. \param tmax maximum distance to the network from 'to'
  881. \param tucfield field with unique categories used in the turntable
  882. \param costs pointer where to store costs on the network (or NULL)
  883. \param Points pointer to the structure where to store vertices of shortest path (or NULL)
  884. \param List pointer to the structure where list of lines on the network is stored (or NULL)
  885. \param NodesList pointer to the structure where list of nodes on the network is stored (or NULL)
  886. \param FPoints pointer to the structure where to store line from 'from' to first network node (or NULL)
  887. \param TPoints pointer to the structure where to store line from last network node to 'to' (or NULL)
  888. \param fdist distance from 'from' to the net (or NULL)
  889. \param tdist distance from 'to' to the net (or NULL)
  890. \return 1 OK, 0 not reachable
  891. */
  892. int
  893. Vect_net_ttb_shortest_path_coor(struct Map_info *Map,
  894. double fx, double fy, double fz, double tx,
  895. double ty, double tz, double fmax,
  896. double tmax, int tucfield,
  897. double *costs, struct line_pnts *Points,
  898. struct ilist *List, struct ilist *NodesList,
  899. struct line_pnts *FPoints,
  900. struct line_pnts *TPoints, double *fdist,
  901. double *tdist)
  902. {
  903. return find_shortest_path_coor(Map, fx, fy, fz, tx, ty, tz, fmax, tmax,
  904. 1, tucfield, costs, Points, List,
  905. NodesList, FPoints, TPoints, fdist, tdist);
  906. }