line.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979
  1. /*!
  2. \file lib/vector/Vlib/line.c
  3. \brief Vector library - vector feature geometry
  4. (C) 2001-2009 by the GRASS Development Team
  5. This program is free software under the GNU General Public License
  6. (>=v2). Read the file COPYING that comes with GRASS for details.
  7. \author Original author CERL, probably Dave Gerdes or Mike Higgins.
  8. \author Update to GRASS 5.7 Radim Blazek and David D. Gray.
  9. \author Some updates for GRASS 7 by Martin Landa <landa.martin gmail.com>
  10. */
  11. #include <stdlib.h>
  12. #include <math.h>
  13. #include <grass/vector.h>
  14. #include <grass/glocale.h>
  15. /*!
  16. \brief Creates and initializes a struct line_pnts (internal use only)
  17. Use Vect_new_line_struct() instead.
  18. \return pointer to allocated line_pnts structure
  19. \return NULL on error
  20. */
  21. struct line_pnts *Vect__new_line_struct(void);
  22. /*!
  23. \brief Creates and initializes a line_pnts structure
  24. This structure is used for reading and writing vector lines and
  25. polygons. The library routines handle all memory allocation. If 3
  26. lines in memory are needed at the same time, then simply 3 line_pnts
  27. structures have to be used.
  28. To free allocated memory call Vect_destroy_line_struct().
  29. Calls G_fatal_error() on error.
  30. \return pointer to line_pnts
  31. */
  32. struct line_pnts *Vect_new_line_struct()
  33. {
  34. struct line_pnts *p;
  35. if (NULL == (p = Vect__new_line_struct()))
  36. G_fatal_error("Vect_new_line_struct(): %s", _("Out of memory"));
  37. return p;
  38. }
  39. struct line_pnts *Vect__new_line_struct()
  40. {
  41. struct line_pnts *p;
  42. p = (struct line_pnts *)malloc(sizeof(struct line_pnts));
  43. /* alloc_points MUST be initialized to zero */
  44. if (p)
  45. p->alloc_points = p->n_points = 0;
  46. if (p)
  47. p->x = p->y = p->z = NULL;
  48. return p;
  49. }
  50. /*!
  51. \brief Frees all memory associated with a line_pnts structure,
  52. including the structure itself
  53. \param p pointer to line_pnts structure
  54. */
  55. void Vect_destroy_line_struct(struct line_pnts *p)
  56. {
  57. if (p) { /* probably a moot test */
  58. if (p->alloc_points) {
  59. G_free((char *)p->x);
  60. G_free((char *)p->y);
  61. G_free((char *)p->z);
  62. }
  63. G_free((char *)p);
  64. }
  65. }
  66. /*!
  67. \brief Copy points from array to line_pnts structure
  68. \param Points pointer to line_ptns structure
  69. \param x,y,z array of coordinates
  70. \param n number of points to be copied
  71. \return 0 on success
  72. \return -1 on out of memory
  73. */
  74. int Vect_copy_xyz_to_pnts(struct line_pnts *Points, const double *x, const double *y,
  75. const double *z, int n)
  76. {
  77. int i;
  78. if (0 > dig_alloc_points(Points, n))
  79. return -1;
  80. for (i = 0; i < n; i++) {
  81. Points->x[i] = x[i];
  82. Points->y[i] = y[i];
  83. if (z != NULL)
  84. Points->z[i] = z[i];
  85. else
  86. Points->z[i] = 0;
  87. Points->n_points = n;
  88. }
  89. return 0;
  90. }
  91. /*!
  92. \brief Reset line
  93. Make sure line structure is clean to be re-used, i.e. it has no
  94. points associated with it Points must have previously been created
  95. with Vect_new_line_struct().
  96. \param Points pointer to line_pnts structure to be reset
  97. */
  98. void Vect_reset_line(struct line_pnts *Points)
  99. {
  100. Points->n_points = 0;
  101. }
  102. /*!
  103. \brief Appends one point to the end of a line.
  104. If you are re-using a line struct, be sure to clear out old data
  105. first by calling Vect_reset_line().
  106. Calls G_fatal_error() when out of memory.
  107. \param Points pointer to line_pnts structure
  108. \param x,y,z point coordinates to be added
  109. \return number of points
  110. \return -1 on error (out of memory)
  111. */
  112. int Vect_append_point(struct line_pnts *Points, double x, double y, double z)
  113. {
  114. register int n;
  115. if (0 > dig_alloc_points(Points, Points->n_points + 1)) {
  116. G_fatal_error(_("Out of memory"));
  117. return -1;
  118. }
  119. n = Points->n_points;
  120. Points->x[n] = x;
  121. Points->y[n] = y;
  122. Points->z[n] = z;
  123. return ++(Points->n_points);
  124. }
  125. /*!
  126. \brief Insert new point at index position and move all old points
  127. at that position and above up
  128. \param Points pointer to line_pnts structure
  129. \param index (from 0 to Points->n_points-1)
  130. \param x,y,z point coordinates
  131. \return number of points
  132. \return -1 on error (alocation)
  133. */
  134. int Vect_line_insert_point(struct line_pnts *Points, int index, double x,
  135. double y, double z)
  136. {
  137. int n;
  138. if (index < 0 || index > Points->n_points - 1)
  139. G_fatal_error("Vect_line_insert_point(): %s",
  140. _("Index out of range in"));
  141. if (0 > dig_alloc_points(Points, Points->n_points + 1))
  142. return -1;
  143. /* move up */
  144. for (n = Points->n_points; n > index; n--) {
  145. Points->x[n] = Points->x[n - 1];
  146. Points->y[n] = Points->y[n - 1];
  147. Points->z[n] = Points->z[n - 1];
  148. }
  149. Points->x[index] = x;
  150. Points->y[index] = y;
  151. Points->z[index] = z;
  152. return ++(Points->n_points);
  153. }
  154. /*!
  155. \brief Delete point at given index and move all points above down
  156. \param Points pointer to line_pnts structure
  157. \param index point (from 0 to Points->n_points-1)
  158. \return number of points
  159. */
  160. int Vect_line_delete_point(struct line_pnts *Points, int index)
  161. {
  162. int n;
  163. if (index < 0 || index > Points->n_points - 1)
  164. G_fatal_error("Vect_line_insert_point(): %s",
  165. _("Index out of range in"));
  166. if (Points->n_points == 0)
  167. return 0;
  168. /* move down */
  169. for (n = index; n < Points->n_points - 1; n++) {
  170. Points->x[n] = Points->x[n + 1];
  171. Points->y[n] = Points->y[n + 1];
  172. Points->z[n] = Points->z[n + 1];
  173. }
  174. return --(Points->n_points);
  175. }
  176. /*!
  177. \brief Get line point of given index
  178. Calls G_fatal_error() when index is not range in.
  179. \param Points pointer to line_pnts structure
  180. \param index point index (from 0 to Points->n_points-1)
  181. \param x pointer to x coordinate or NULL
  182. \param y pointer to y coordinate or NULL
  183. \param z pointer to z coordinate or NULL
  184. \return number of points
  185. */
  186. int Vect_line_get_point(const struct line_pnts *Points, int index,
  187. double *x, double *y, double *z)
  188. {
  189. if (index < 0 || index > Points->n_points - 1)
  190. G_fatal_error("Vect_line_get_point(): %s",
  191. _("Index out of range in"));
  192. if (x)
  193. *x = Points->x[index];
  194. if (y)
  195. *y = Points->y[index];
  196. if (z)
  197. *z = Points->z[index];
  198. return Points->n_points;
  199. }
  200. /*!
  201. \brief Get number of line points
  202. \param Points pointer to line_pnts structure
  203. \return number of points
  204. */
  205. int Vect_get_num_line_points(const struct line_pnts *Points)
  206. {
  207. return Points->n_points;
  208. }
  209. /*!
  210. \brief Remove duplicate points, i.e. zero length segments
  211. \param Points pointer to line_pnts structure
  212. \return number of points
  213. */
  214. int Vect_line_prune(struct line_pnts *Points)
  215. {
  216. int i, j;
  217. if (Points->n_points > 0) {
  218. j = 1;
  219. for (i = 1; i < Points->n_points; i++) {
  220. if (Points->x[i] != Points->x[j - 1] ||
  221. Points->y[i] != Points->y[j - 1]
  222. || Points->z[i] != Points->z[j - 1]) {
  223. Points->x[j] = Points->x[i];
  224. Points->y[j] = Points->y[i];
  225. Points->z[j] = Points->z[i];
  226. j++;
  227. }
  228. }
  229. Points->n_points = j;
  230. }
  231. return (Points->n_points);
  232. }
  233. /*!
  234. \brief Remove points in threshold
  235. \param Points pointer to line_pnts structure
  236. \param threshold threshold value
  237. \return number of points in result
  238. */
  239. int Vect_line_prune_thresh(struct line_pnts *Points, double threshold)
  240. {
  241. int ret;
  242. ret = dig_prune(Points, threshold);
  243. if (ret < Points->n_points)
  244. Points->n_points = ret;
  245. return (Points->n_points);
  246. }
  247. /*!
  248. \brief Appends points to the end of a line.
  249. Note, this will append to whatever is in line_pnts structure. If you
  250. are re-using a line struct, be sure to clear out old data first by
  251. calling Vect_reset_line().
  252. \param Points pointer to line_pnts structure
  253. \param APoints points to be included
  254. \param direction direction (GV_FORWARD, GV_BACKWARD)
  255. \return new number of points
  256. \return -1 on out of memory
  257. */
  258. int Vect_append_points(struct line_pnts *Points, const struct line_pnts *APoints,
  259. int direction)
  260. {
  261. int i, n, on, an;
  262. on = Points->n_points;
  263. an = APoints->n_points;
  264. n = on + an;
  265. /* Should be OK, dig_alloc_points calls realloc */
  266. if (0 > dig_alloc_points(Points, n))
  267. return (-1);
  268. if (direction == GV_FORWARD) {
  269. for (i = 0; i < an; i++) {
  270. Points->x[on + i] = APoints->x[i];
  271. Points->y[on + i] = APoints->y[i];
  272. Points->z[on + i] = APoints->z[i];
  273. }
  274. }
  275. else {
  276. for (i = 0; i < an; i++) {
  277. Points->x[on + i] = APoints->x[an - i - 1];
  278. Points->y[on + i] = APoints->y[an - i - 1];
  279. Points->z[on + i] = APoints->z[an - i - 1];
  280. }
  281. }
  282. Points->n_points = n;
  283. return n;
  284. }
  285. /*!
  286. \brief Copy points from line structure to array
  287. x/y/z arrays MUST be at least as large as Points->n_points
  288. Also note that n is a pointer to int.
  289. \param Points pointer to line_pnts structure
  290. \param x,y,z coordinates arrays
  291. \param n number of points
  292. \return number of points copied
  293. */
  294. int Vect_copy_pnts_to_xyz(const struct line_pnts *Points, double *x, double *y,
  295. double *z, int *n)
  296. {
  297. int i;
  298. for (i = 0; i < *n; i++) {
  299. x[i] = Points->x[i];
  300. y[i] = Points->y[i];
  301. if (z != NULL)
  302. z[i] = Points->z[i];
  303. *n = Points->n_points;
  304. }
  305. return (Points->n_points);
  306. }
  307. /*!
  308. \brief Find point on line in the specified distance.
  309. From the beginning, measured along line.
  310. If the distance is greater than line length or negative, error is returned.
  311. \param Points pointer to line_pnts structure
  312. \param distance distance value
  313. \param x,y,z pointers to point coordinates or NULL
  314. \param angle pointer to angle of line in that point (radians, counter clockwise from x axis) or NULL
  315. \param slope pointer to slope angle in radians (positive up)
  316. \return number of segment the point is on (first is 1),
  317. \return 0 error when point is outside the line
  318. */
  319. int Vect_point_on_line(const struct line_pnts *Points, double distance,
  320. double *x, double *y, double *z, double *angle,
  321. double *slope)
  322. {
  323. int j, np, seg = 0;
  324. double dist = 0, length;
  325. double xp = 0, yp = 0, zp = 0, dx = 0, dy = 0, dz = 0, dxy =
  326. 0, dxyz, k, rest;
  327. G_debug(3, "Vect_point_on_line(): distance = %f", distance);
  328. if ((distance < 0) || (Points->n_points < 2))
  329. return 0;
  330. /* Check if first or last */
  331. length = Vect_line_length(Points);
  332. G_debug(3, " length = %f", length);
  333. if (distance < 0 || distance > length) {
  334. G_debug(3, " -> outside line");
  335. return 0;
  336. }
  337. np = Points->n_points;
  338. if (distance == 0) {
  339. G_debug(3, " -> first point");
  340. xp = Points->x[0];
  341. yp = Points->y[0];
  342. zp = Points->z[0];
  343. dx = Points->x[1] - Points->x[0];
  344. dy = Points->y[1] - Points->y[0];
  345. dz = Points->z[1] - Points->z[0];
  346. dxy = hypot(dx, dy);
  347. seg = 1;
  348. }
  349. else if (distance == length) {
  350. G_debug(3, " -> last point");
  351. xp = Points->x[np - 1];
  352. yp = Points->y[np - 1];
  353. zp = Points->z[np - 1];
  354. dx = Points->x[np - 1] - Points->x[np - 2];
  355. dy = Points->y[np - 1] - Points->y[np - 2];
  356. dz = Points->z[np - 1] - Points->z[np - 2];
  357. dxy = hypot(dx, dy);
  358. seg = np - 1;
  359. }
  360. else {
  361. for (j = 0; j < Points->n_points - 1; j++) {
  362. /* dxyz = G_distance(Points->x[j], Points->y[j],
  363. Points->x[j+1], Points->y[j+1]); */
  364. dx = Points->x[j + 1] - Points->x[j];
  365. dy = Points->y[j + 1] - Points->y[j];
  366. dz = Points->z[j + 1] - Points->z[j];
  367. dxy = hypot(dx, dy);
  368. dxyz = hypot(dxy, dz);
  369. dist += dxyz;
  370. if (dist >= distance) { /* point is on the current line part */
  371. rest = distance - dist + dxyz; /* from first point of segment to point */
  372. k = rest / dxyz;
  373. xp = Points->x[j] + k * dx;
  374. yp = Points->y[j] + k * dy;
  375. zp = Points->z[j] + k * dz;
  376. seg = j + 1;
  377. break;
  378. }
  379. }
  380. }
  381. if (x != NULL)
  382. *x = xp;
  383. if (y != NULL)
  384. *y = yp;
  385. if (z != NULL)
  386. *z = zp;
  387. /* calculate angle */
  388. if (angle != NULL)
  389. *angle = atan2(dy, dx);
  390. /* calculate slope */
  391. if (slope != NULL)
  392. *slope = atan2(dz, dxy);
  393. return seg;
  394. }
  395. /*!
  396. \brief Create line segment.
  397. Creates segment of InPoints from start to end measured along the
  398. line and write it to OutPoints.
  399. If the distance is greater than line length or negative, error is
  400. returned.
  401. \param InPoints input line
  402. \param start segment number
  403. \param end segment number
  404. \param OutPoints output line
  405. \return 1 success
  406. \return 0 error when start > length or end < 0 or start < 0 or end > length
  407. */
  408. int Vect_line_segment(const struct line_pnts *InPoints, double start, double end,
  409. struct line_pnts *OutPoints)
  410. {
  411. int i, seg1, seg2;
  412. double length, tmp;
  413. double x1, y1, z1, x2, y2, z2;
  414. G_debug(3, "Vect_line_segment(): start = %f, end = %f, n_points = %d",
  415. start, end, InPoints->n_points);
  416. Vect_reset_line(OutPoints);
  417. if (start > end) {
  418. tmp = start;
  419. start = end;
  420. end = tmp;
  421. }
  422. /* Check start/end */
  423. if (end < 0)
  424. return 0;
  425. length = Vect_line_length(InPoints);
  426. if (start > length)
  427. return 0;
  428. /* Find coordinates and segments of start/end */
  429. seg1 = Vect_point_on_line(InPoints, start, &x1, &y1, &z1, NULL, NULL);
  430. seg2 = Vect_point_on_line(InPoints, end, &x2, &y2, &z2, NULL, NULL);
  431. G_debug(3, " -> seg1 = %d seg2 = %d", seg1, seg2);
  432. if (seg1 == 0 || seg2 == 0) {
  433. G_warning(_("Segment outside line, no segment created"));
  434. return 0;
  435. }
  436. Vect_append_point(OutPoints, x1, y1, z1);
  437. for (i = seg1; i < seg2; i++) {
  438. Vect_append_point(OutPoints, InPoints->x[i], InPoints->y[i],
  439. InPoints->z[i]);
  440. };
  441. Vect_append_point(OutPoints, x2, y2, z2);
  442. Vect_line_prune(OutPoints);
  443. return 1;
  444. }
  445. /*!
  446. \brief Calculate line length, 3D-length in case of 3D vector line
  447. For Lat-Long use Vect_line_geodesic_length() instead.
  448. \param Points pointer to line_pnts structure geometry
  449. \return line length
  450. */
  451. double Vect_line_length(const struct line_pnts *Points)
  452. {
  453. int j;
  454. double dx, dy, dz, len = 0;
  455. if (Points->n_points < 2)
  456. return 0;
  457. for (j = 0; j < Points->n_points - 1; j++) {
  458. dx = Points->x[j + 1] - Points->x[j];
  459. dy = Points->y[j + 1] - Points->y[j];
  460. dz = Points->z[j + 1] - Points->z[j];
  461. len += hypot(hypot(dx, dy), dz);
  462. }
  463. return len;
  464. }
  465. /*!
  466. \brief Calculate line length.
  467. If projection is LL, the length is measured along the geodesic.
  468. \param Points pointer to line_pnts structure geometry
  469. \return line length
  470. */
  471. double Vect_line_geodesic_length(const struct line_pnts *Points)
  472. {
  473. int j, dc;
  474. double dx, dy, dz, dxy, len = 0;
  475. dc = G_begin_distance_calculations();
  476. if (Points->n_points < 2)
  477. return 0;
  478. for (j = 0; j < Points->n_points - 1; j++) {
  479. if (dc == 2)
  480. dxy =
  481. G_geodesic_distance(Points->x[j], Points->y[j],
  482. Points->x[j + 1], Points->y[j + 1]);
  483. else {
  484. dx = Points->x[j + 1] - Points->x[j];
  485. dy = Points->y[j + 1] - Points->y[j];
  486. dxy = hypot(dx, dy);
  487. }
  488. dz = Points->z[j + 1] - Points->z[j];
  489. len += hypot(dxy, dz);
  490. }
  491. return len;
  492. }
  493. /*!
  494. \brief Calculate distance of point to line.
  495. Sets (if not null):
  496. - px, py - point on line,
  497. - dist - distance to line,
  498. - spdist - distance to point on line from segment beginning,
  499. - lpdist - distance to point on line from line beginning along line
  500. \param points pointer to line_pnts structure
  501. \param ux,uy,uz point coordinates
  502. \param with_z flag if to use z coordinate (3D calculation)
  503. \param[out] px,py,pz point on line
  504. \param[out] dist distance to line
  505. \param[out] spdist distance to point on line from segment beginning
  506. \param[out] lpdist distance to point on line from line beginning along line
  507. \return nearest segment (first is 1)
  508. */
  509. int Vect_line_distance(const struct line_pnts *points,
  510. double ux, double uy, double uz,
  511. int with_z,
  512. double *px, double *py, double *pz,
  513. double *dist, double *spdist, double *lpdist)
  514. {
  515. int i;
  516. double distance;
  517. double new_dist;
  518. double tpx, tpy, tpz, tdist, tspdist, tlpdist = 0;
  519. double dx, dy, dz;
  520. int n_points;
  521. int segment;
  522. n_points = points->n_points;
  523. if (n_points == 1) {
  524. distance =
  525. dig_distance2_point_to_line(ux, uy, uz, points->x[0],
  526. points->y[0], points->z[0],
  527. points->x[0], points->y[0],
  528. points->z[0], with_z, NULL, NULL,
  529. NULL, NULL, NULL);
  530. tpx = points->x[0];
  531. tpy = points->y[0];
  532. tpz = points->z[0];
  533. tdist = sqrt(distance);
  534. tspdist = 0;
  535. tlpdist = 0;
  536. segment = 0;
  537. }
  538. else {
  539. distance =
  540. dig_distance2_point_to_line(ux, uy, uz, points->x[0],
  541. points->y[0], points->z[0],
  542. points->x[1], points->y[1],
  543. points->z[1], with_z, NULL, NULL,
  544. NULL, NULL, NULL);
  545. segment = 1;
  546. for (i = 1; i < n_points - 1; i++) {
  547. new_dist = dig_distance2_point_to_line(ux, uy, uz,
  548. points->x[i], points->y[i],
  549. points->z[i],
  550. points->x[i + 1],
  551. points->y[i + 1],
  552. points->z[i + 1], with_z,
  553. NULL, NULL, NULL, NULL,
  554. NULL);
  555. if (new_dist < distance) {
  556. distance = new_dist;
  557. segment = i + 1;
  558. }
  559. }
  560. /* we have segment and now we can recalculate other values (speed) */
  561. new_dist = dig_distance2_point_to_line(ux, uy, uz,
  562. points->x[segment - 1],
  563. points->y[segment - 1],
  564. points->z[segment - 1],
  565. points->x[segment],
  566. points->y[segment],
  567. points->z[segment], with_z,
  568. &tpx, &tpy, &tpz, &tspdist,
  569. NULL);
  570. /* calculate distance from beginning of line */
  571. if (lpdist) {
  572. tlpdist = 0;
  573. for (i = 0; i < segment - 1; i++) {
  574. dx = points->x[i + 1] - points->x[i];
  575. dy = points->y[i + 1] - points->y[i];
  576. if (with_z)
  577. dz = points->z[i + 1] - points->z[i];
  578. else
  579. dz = 0;
  580. tlpdist += hypot(hypot(dx, dy), dz);
  581. }
  582. tlpdist += tspdist;
  583. }
  584. tdist = sqrt(distance);
  585. }
  586. if (px)
  587. *px = tpx;
  588. if (py)
  589. *py = tpy;
  590. if (pz && with_z)
  591. *pz = tpz;
  592. if (dist)
  593. *dist = tdist;
  594. if (spdist)
  595. *spdist = tspdist;
  596. if (lpdist)
  597. *lpdist = tlpdist;
  598. return (segment);
  599. }
  600. /*!
  601. \brief Calculate geodesic distance of point to line in meters.
  602. Sets (if not null):
  603. - px, py - point on line,
  604. - dist - distance to line,
  605. - spdist - distance to point on line from segment beginning,
  606. - lpdist - distance to point on line from line beginning along line
  607. \param points pointer to line_pnts structure
  608. \param ux,uy,uz point coordinates
  609. \param with_z flag if to use z coordinate (3D calculation)
  610. \param[out] px,py,pz point on line
  611. \param[out] dist distance to line
  612. \param[out] spdist distance to point on line from segment beginning
  613. \param[out] lpdist distance to point on line from line beginning along line
  614. \return nearest segment (first is 1)
  615. */
  616. int Vect_line_geodesic_distance(const struct line_pnts *points,
  617. double ux, double uy, double uz,
  618. int with_z,
  619. double *px, double *py, double *pz,
  620. double *dist, double *spdist,
  621. double *lpdist)
  622. {
  623. int i;
  624. double distance;
  625. double new_dist;
  626. double tpx, tpy, tpz, ttpx, ttpy, ttpz;
  627. double tdist, tspdist, tlpdist = 0, tlpdistseg;
  628. double dz;
  629. int n_points;
  630. int segment;
  631. G_begin_distance_calculations();
  632. n_points = points->n_points;
  633. if (n_points == 1) {
  634. distance = G_distance(ux, uy, points->x[0], points->y[0]);
  635. if (with_z)
  636. distance = hypot(distance, uz - points->z[0]);
  637. tpx = points->x[0];
  638. tpy = points->y[0];
  639. tpz = points->z[0];
  640. tdist = distance;
  641. tspdist = 0;
  642. tlpdist = 0;
  643. segment = 0;
  644. }
  645. else {
  646. distance =
  647. dig_distance2_point_to_line(ux, uy, uz, points->x[0],
  648. points->y[0], points->z[0],
  649. points->x[1], points->y[1],
  650. points->z[1], with_z,
  651. &tpx, &tpy, &tpz,
  652. NULL, NULL);
  653. distance = G_distance(ux, uy, tpx, tpy);
  654. if (with_z)
  655. distance = hypot(distance, uz - tpz);
  656. segment = 1;
  657. for (i = 1; i < n_points - 1; i++) {
  658. new_dist = dig_distance2_point_to_line(ux, uy, uz,
  659. points->x[i], points->y[i],
  660. points->z[i],
  661. points->x[i + 1],
  662. points->y[i + 1],
  663. points->z[i + 1], with_z,
  664. &ttpx, &ttpy, &ttpz,
  665. NULL, NULL);
  666. new_dist = G_distance(ux, uy, ttpx, ttpy);
  667. if (with_z)
  668. new_dist = hypot(new_dist, uz - ttpz);
  669. if (new_dist < distance) {
  670. distance = new_dist;
  671. segment = i + 1;
  672. tpx = ttpx;
  673. tpy = ttpy;
  674. tpz = ttpz;
  675. }
  676. }
  677. /* calculate distance from beginning of segment */
  678. tspdist = G_distance(points->x[segment - 1], points->y[segment - 1],
  679. tpx, tpy);
  680. if (with_z) {
  681. dz = points->z[segment - 1] - tpz;
  682. tspdist += hypot(tspdist, dz);
  683. }
  684. /* calculate distance from beginning of line */
  685. if (lpdist) {
  686. tlpdist = 0;
  687. for (i = 0; i < segment - 1; i++) {
  688. tlpdistseg = G_distance(points->x[i], points->y[i],
  689. points->x[i + 1], points->y[i + 1]);
  690. if (with_z) {
  691. dz = points->z[i + 1] - points->z[i];
  692. tlpdistseg += hypot(tlpdistseg, dz);
  693. }
  694. tlpdist += tlpdistseg;
  695. }
  696. tlpdist += tspdist;
  697. }
  698. tdist = distance;
  699. }
  700. if (px)
  701. *px = tpx;
  702. if (py)
  703. *py = tpy;
  704. if (pz && with_z)
  705. *pz = tpz;
  706. if (dist)
  707. *dist = tdist;
  708. if (spdist)
  709. *spdist = tspdist;
  710. if (lpdist)
  711. *lpdist = tlpdist;
  712. return (segment);
  713. }
  714. /*!
  715. \brief Calculate distance of 2 points
  716. Simply uses Pythagoras.
  717. \param x1,y1,z1 first point
  718. \param x2,y2,z2 second point
  719. \param with_z use z coordinate
  720. \return distance
  721. */
  722. double Vect_points_distance(double x1, double y1, double z1, /* point 1 */
  723. double x2, double y2, double z2, /* point 2 */
  724. int with_z)
  725. {
  726. double dx, dy, dz;
  727. dx = x2 - x1;
  728. dy = y2 - y1;
  729. dz = z2 - z1;
  730. if (with_z)
  731. return hypot(hypot(dx, dy), dz);
  732. else
  733. return hypot(dx, dy);
  734. }
  735. /*!
  736. \brief Get bounding box of line
  737. \param Points pointer to line_pnts structure
  738. \param[out] Box bounding box
  739. */
  740. void Vect_line_box(const struct line_pnts *Points, struct bound_box *Box)
  741. {
  742. dig_line_box(Points, Box);
  743. }
  744. /*!
  745. \brief Reverse the order of vertices
  746. \param Points pointer to line_pnts structure to be changed
  747. */
  748. void Vect_line_reverse(struct line_pnts *Points)
  749. {
  750. int i, j, np;
  751. double x, y, z;
  752. np = (int)Points->n_points / 2;
  753. for (i = 0; i < np; i++) {
  754. j = Points->n_points - i - 1;
  755. x = Points->x[i];
  756. y = Points->y[i];
  757. z = Points->z[i];
  758. Points->x[i] = Points->x[j];
  759. Points->y[i] = Points->y[j];
  760. Points->z[i] = Points->z[j];
  761. Points->x[j] = x;
  762. Points->y[j] = y;
  763. Points->z[j] = z;
  764. }
  765. }
  766. /*!
  767. \brief Fetches FIRST category number for given vector line and field
  768. \param Map pointer to Map_info structure
  769. \param line line id
  770. \param field layer number
  771. \return -1 no category
  772. \return category number (>=0)
  773. */
  774. int Vect_get_line_cat(const struct Map_info *Map, int line, int field)
  775. {
  776. static struct line_cats *cats = NULL;
  777. int cat, ltype;
  778. if (cats == NULL)
  779. cats = Vect_new_cats_struct();
  780. ltype = Vect_read_line(Map, NULL, cats, line);
  781. Vect_cat_get(cats, field, &cat);
  782. G_debug(3, "Vect_get_line_cat: display line %d, ltype %d, cat %d", line,
  783. ltype, cat);
  784. return cat;
  785. }