intersect.c 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469
  1. /*!
  2. \file lib/vector/Vlib/intersect.c
  3. \brief Vector library - intersection
  4. Higher level functions for reading/writing/manipulating vectors.
  5. Some parts of code taken from grass50 v.spag/linecros.c
  6. Based on the following:
  7. <code>
  8. (ax2-ax1)r1 - (bx2-bx1)r2 = ax2 - ax1
  9. (ay2-ay1)r1 - (by2-by1)r2 = ay2 - ay1
  10. </code>
  11. Solving for r1 and r2, if r1 and r2 are between 0 and 1, then line
  12. segments (ax1,ay1)(ax2,ay2) and (bx1,by1)(bx2,by2) intersect.
  13. Intersect 2 line segments.
  14. Returns: 0 - do not intersect
  15. 1 - intersect at one point
  16. <pre>
  17. \ / \ / \ /
  18. \/ \/ \/
  19. /\ \
  20. / \ \
  21. 2 - partial overlap ( \/ )
  22. ------ a ( distance < threshold )
  23. ------ b ( )
  24. 3 - a contains b ( /\ )
  25. ---------- a ----------- a
  26. ---- b ----- b
  27. 4 - b contains a
  28. ---- a ----- a
  29. ---------- b ----------- b
  30. 5 - identical
  31. ---------- a
  32. ---------- b
  33. </pre>
  34. Intersection points:
  35. <pre>
  36. return point1 breakes: point2 breaks: distance1 on: distance2 on:
  37. 0 - - - -
  38. 1 a,b - a b
  39. 2 a b a b
  40. 3 a a a a
  41. 4 b b b b
  42. 5 - - - -
  43. </pre>
  44. Sometimes (often) is important to get the same coordinates for a x
  45. b and b x a. To reach this, the segments a,b are 'sorted' at the
  46. beginning, so that for the same switched segments, results are
  47. identical. (reason is that double values are always rounded because
  48. of limited number of decimal places and for different order of
  49. coordinates, the results would be different)
  50. (C) 2001-2009 by the GRASS Development Team
  51. This program is free software under the GNU General Public License
  52. (>=v2). Read the file COPYING that comes with GRASS for details.
  53. \author Original author CERL, probably Dave Gerdes or Mike Higgins.
  54. \author Update to GRASS 5.7 Radim Blazek.
  55. */
  56. #include <stdlib.h>
  57. #include <stdio.h>
  58. #include <unistd.h>
  59. #include <math.h>
  60. #include <grass/vector.h>
  61. #include <grass/glocale.h>
  62. /* function prototypes */
  63. static int cmp_cross(const void *pa, const void *pb);
  64. static void add_cross(int asegment, double adistance, int bsegment,
  65. double bdistance, double x, double y);
  66. static double dist2(double x1, double y1, double x2, double y2);
  67. static int debug_level = -1;
  68. #if 0
  69. static int ident(double x1, double y1, double x2, double y2, double thresh);
  70. #endif
  71. static int cross_seg(int id, const struct RTree_Rect *rect, void *arg);
  72. static int find_cross(int id, const struct RTree_Rect *rect, void *arg);
  73. #define D ((ax2-ax1)*(by1-by2) - (ay2-ay1)*(bx1-bx2))
  74. #define D1 ((bx1-ax1)*(by1-by2) - (by1-ay1)*(bx1-bx2))
  75. #define D2 ((ax2-ax1)*(by1-ay1) - (ay2-ay1)*(bx1-ax1))
  76. /*!
  77. * \brief Check for intersect of 2 line segments.
  78. *
  79. * \param ax1,ay1,az1,ax2,ay2,az2 input line a
  80. * \param bx1,by1,bz1,bx2,by2,bz2 input line b
  81. * \param[out] x1,y1,z1 intersection point1 (case 2-4)
  82. * \param[out] x2,y2,z2 intersection point2 (case 2-4)
  83. * \param with_z use z coordinate (3D) (TODO)
  84. *
  85. * \return 0 - do not intersect,
  86. * \return 1 - intersect at one point,
  87. * \return 2 - partial overlap,
  88. * \return 3 - a contains b,
  89. * \return 4 - b contains a,
  90. * \return 5 - identical
  91. */
  92. int Vect_segment_intersection(double ax1, double ay1, double az1, double ax2,
  93. double ay2, double az2, double bx1, double by1,
  94. double bz1, double bx2, double by2, double bz2,
  95. double *x1, double *y1, double *z1, double *x2,
  96. double *y2, double *z2, int with_z)
  97. {
  98. static int first_3d = 1;
  99. double d, d1, d2, r1, dtol, t;
  100. int switched;
  101. int end_points;
  102. /* TODO: Works for points ? */
  103. G_debug(4, "Vect_segment_intersection()");
  104. G_debug(4, " %.15g , %.15g - %.15g , %.15g", ax1, ay1, ax2, ay2);
  105. G_debug(4, " %.15g , %.15g - %.15g , %.15g", bx1, by1, bx2, by2);
  106. /* TODO 3D */
  107. if (with_z && first_3d) {
  108. G_warning(_("3D not supported by Vect_segment_intersection()"));
  109. first_3d = 0;
  110. }
  111. *x1 = 0;
  112. *y1 = 0;
  113. *z1 = 0;
  114. *x2 = 0;
  115. *y2 = 0;
  116. *z2 = 0;
  117. /* 'Sort' each segment by x, y
  118. * MUST happen before D, D1, D2 are calculated */
  119. switched = 0;
  120. if (bx2 < bx1)
  121. switched = 1;
  122. else if (bx2 == bx1) {
  123. if (by2 < by1)
  124. switched = 1;
  125. }
  126. if (switched) {
  127. t = bx1;
  128. bx1 = bx2;
  129. bx2 = t;
  130. t = by1;
  131. by1 = by2;
  132. by2 = t;
  133. t = bz1;
  134. bz1 = bz2;
  135. bz2 = t;
  136. }
  137. switched = 0;
  138. if (ax2 < ax1)
  139. switched = 1;
  140. else if (ax2 == ax1) {
  141. if (ay2 < ay1)
  142. switched = 1;
  143. }
  144. if (switched) {
  145. t = ax1;
  146. ax1 = ax2;
  147. ax2 = t;
  148. t = ay1;
  149. ay1 = ay2;
  150. ay2 = t;
  151. t = az1;
  152. az1 = az2;
  153. az2 = t;
  154. }
  155. /* Check for identical segments */
  156. if (ax1 == bx1 && ay1 == by1 && ax2 == bx2 && ay2 == by2) {
  157. G_debug(2, " -> identical segments");
  158. *x1 = ax1;
  159. *y1 = ay1;
  160. *z1 = az1;
  161. *x2 = ax2;
  162. *y2 = ay2;
  163. *z2 = az2;
  164. return 5;
  165. }
  166. /* 'Sort' segments by x, y: make sure a <= b
  167. * MUST happen before D, D1, D2 are calculated */
  168. switched = 0;
  169. if (bx1 < ax1)
  170. switched = 1;
  171. else if (bx1 == ax1) {
  172. if (bx2 < ax2)
  173. switched = 1;
  174. else if (bx2 == ax2) {
  175. if (by1 < ay1)
  176. switched = 1;
  177. else if (by1 == ay1) {
  178. if (by2 < ay2)
  179. switched = 1;
  180. }
  181. }
  182. }
  183. if (switched) {
  184. t = ax1;
  185. ax1 = bx1;
  186. bx1 = t;
  187. t = ax2;
  188. ax2 = bx2;
  189. bx2 = t;
  190. t = ay1;
  191. ay1 = by1;
  192. by1 = t;
  193. t = ay2;
  194. ay2 = by2;
  195. by2 = t;
  196. t = az1;
  197. az1 = bz1;
  198. bz1 = t;
  199. t = az2;
  200. az2 = bz2;
  201. bz2 = t;
  202. }
  203. d = D;
  204. d1 = D1;
  205. d2 = D2;
  206. G_debug(2, "Vect_segment_intersection(): d = %f, d1 = %f, d2 = %f", d, d1,
  207. d2);
  208. end_points = 0;
  209. if (ax1 == bx1 && ay1 == by1) {
  210. end_points = 1;
  211. *x1 = ax1;
  212. *y1 = ay1;
  213. }
  214. if (ax1 == bx2 && ay1 == by2) {
  215. end_points = 1;
  216. *x1 = ax1;
  217. *y1 = ay1;
  218. }
  219. if (ax2 == bx1 && ay2 == by1) {
  220. end_points = 2;
  221. *x1 = ax2;
  222. *y1 = ay2;
  223. }
  224. if (ax2 == bx2 && ay2 == by2) {
  225. end_points = 2;
  226. *x1 = ax2;
  227. *y1 = ay2;
  228. }
  229. /* TODO: dtol was originally set to 1.0e-10, which was usually working but not always.
  230. * Can it be a problem to set the tolerance to 0.0 ? */
  231. dtol = 0.0;
  232. if (fabs(d) > dtol) {
  233. G_debug(2, " -> not parallel/collinear: d1 = %f, d2 = %f", d1, d2);
  234. if (d > 0) {
  235. if (d1 < 0 || d1 > d || d2 < 0 || d2 > d) {
  236. if (end_points) {
  237. G_debug(2, " -> fp error, but intersection at end points %f, %f", *x1, *y1);
  238. return 1;
  239. }
  240. else {
  241. G_debug(2, " -> no intersection");
  242. return 0;
  243. }
  244. }
  245. }
  246. else {
  247. if (d1 < d || d1 > 0 || d2 < d || d2 > 0) {
  248. if (end_points) {
  249. G_debug(2, " -> fp error, but intersection at end points %f, %f", *x1, *y1);
  250. return 1;
  251. }
  252. else {
  253. G_debug(2, " -> no intersection");
  254. return 0;
  255. }
  256. }
  257. }
  258. r1 = d1 / d;
  259. *x1 = ax1 + r1 * (ax2 - ax1);
  260. *y1 = ay1 + r1 * (ay2 - ay1);
  261. *z1 = 0;
  262. G_debug(2, " -> intersection %f, %f", *x1, *y1);
  263. return 1;
  264. }
  265. /* segments are parallel or collinear */
  266. G_debug(3, " -> parallel/collinear");
  267. if (d1 || d2) { /* lines are parallel */
  268. G_debug(2, " -> parallel");
  269. if (end_points)
  270. G_debug(2, "Segments are apparently parallel, but connected at end points -> collinear");
  271. else
  272. return 0;
  273. }
  274. /* segments are colinear. check for overlap */
  275. /* Collinear vertical */
  276. /* original code assumed lines were not both vertical
  277. * so there is a special case if they are */
  278. if (ax1 == ax2) {
  279. G_debug(2, " -> collinear vertical");
  280. if (ay1 > by2 || ay2 < by1) {
  281. G_debug(2, " -> no intersection");
  282. return 0;
  283. }
  284. /* end points */
  285. if (ay1 == by2) {
  286. G_debug(2, " -> connected by end points");
  287. *x1 = ax1;
  288. *y1 = ay1;
  289. *z1 = 0;
  290. return 1; /* endpoints only */
  291. }
  292. if (ay2 == by1) {
  293. G_debug(2, " -> connected by end points");
  294. *x1 = ax2;
  295. *y1 = ay2;
  296. *z1 = 0;
  297. return 1; /* endpoints only */
  298. }
  299. /* general overlap */
  300. G_debug(3, " -> vertical overlap");
  301. /* a contains b */
  302. if (ay1 <= by1 && ay2 >= by2) {
  303. G_debug(2, " -> a contains b");
  304. *x1 = bx1;
  305. *y1 = by1;
  306. *z1 = 0;
  307. *x2 = bx2;
  308. *y2 = by2;
  309. *z2 = 0;
  310. return 3;
  311. }
  312. /* b contains a */
  313. if (ay1 >= by1 && ay2 <= by2) {
  314. G_debug(2, " -> b contains a");
  315. *x1 = ax1;
  316. *y1 = ay1;
  317. *z1 = 0;
  318. *x2 = ax2;
  319. *y2 = ay2;
  320. *z2 = 0;
  321. return 4;
  322. }
  323. /* general overlap, 2 intersection points */
  324. G_debug(2, " -> partial overlap");
  325. if (by1 > ay1 && by1 < ay2) { /* b1 in a */
  326. G_debug(2, " -> b1 in a");
  327. *x1 = bx1;
  328. *y1 = by1;
  329. *z1 = 0;
  330. *x2 = ax2;
  331. *y2 = ay2;
  332. *z2 = 0;
  333. return 2;
  334. }
  335. if (by2 > ay1 && by2 < ay2) { /* b2 in a */
  336. G_debug(2, " -> b2 in a");
  337. *x1 = ax1;
  338. *y1 = ay1;
  339. *z1 = 0;
  340. *x2 = bx2;
  341. *y2 = by2;
  342. *z2 = 0;
  343. return 2;
  344. }
  345. /* should not be reached */
  346. G_warning(_("Vect_segment_intersection() ERROR (collinear vertical segments)"));
  347. G_warning("a");
  348. G_warning("%.15g %.15g", ax1, ay1);
  349. G_warning("%.15g %.15g", ax2, ay2);
  350. G_warning("b");
  351. G_warning("%.15g %.15g", bx1, by1);
  352. G_warning("%.15g %.15g", bx2, by2);
  353. return 0;
  354. }
  355. /* Collinear non vertical */
  356. G_debug(2, " -> collinear non vertical");
  357. /* b is to the left or right of a */
  358. if ((bx1 > ax2) || (bx2 < ax1)) {
  359. /* should not happen if segments are selected from rtree */
  360. G_debug(2, " -> no intersection");
  361. return 0;
  362. }
  363. /* there is overlap or connected end points */
  364. G_debug(2, " -> overlap/connected end points");
  365. /* end points */
  366. if (ax1 == bx2 && ay1 == by2) {
  367. G_debug(2, " -> connected by end points");
  368. *x1 = ax1;
  369. *y1 = ay1;
  370. *z1 = 0;
  371. return 1;
  372. }
  373. if (ax2 == bx1 && ay2 == by1) {
  374. G_debug(2, " -> connected by end points");
  375. *x1 = ax2;
  376. *y1 = ay2;
  377. *z1 = 0;
  378. return 1;
  379. }
  380. /* a contains b */
  381. if (ax1 <= bx1 && ax2 >= bx2) {
  382. G_debug(2, " -> a contains b");
  383. *x1 = bx1;
  384. *y1 = by1;
  385. *z1 = 0;
  386. *x2 = bx2;
  387. *y2 = by2;
  388. *z2 = 0;
  389. return 3;
  390. }
  391. /* b contains a */
  392. if (ax1 >= bx1 && ax2 <= bx2) {
  393. G_debug(2, " -> b contains a");
  394. *x1 = ax1;
  395. *y1 = ay1;
  396. *z1 = 0;
  397. *x2 = ax2;
  398. *y2 = ay2;
  399. *z2 = 0;
  400. return 4;
  401. }
  402. /* general overlap, 2 intersection points (lines are not vertical) */
  403. G_debug(2, " -> partial overlap");
  404. if (bx1 > ax1 && bx1 < ax2) { /* b1 is in a */
  405. G_debug(2, " -> b1 in a");
  406. *x1 = bx1;
  407. *y1 = by1;
  408. *z1 = 0;
  409. *x2 = ax2;
  410. *y2 = ay2;
  411. *z2 = 0;
  412. return 2;
  413. }
  414. if (bx2 > ax1 && bx2 < ax2) { /* b2 is in a */
  415. G_debug(2, " -> b2 in a");
  416. *x1 = ax1;
  417. *y1 = ay1;
  418. *z1 = 0;
  419. *x2 = bx2;
  420. *y2 = by2;
  421. *z2 = 0;
  422. return 2;
  423. }
  424. /* should not be reached */
  425. G_warning(_("Vect_segment_intersection() ERROR (collinear non vertical segments)"));
  426. G_warning("a");
  427. G_warning("%.15g %.15g", ax1, ay1);
  428. G_warning("%.15g %.15g", ax2, ay2);
  429. G_warning("b");
  430. G_warning("%.15g %.15g", bx1, by1);
  431. G_warning("%.15g %.15g", bx2, by2);
  432. return 0;
  433. }
  434. typedef struct
  435. { /* in arrays 0 - A line , 1 - B line */
  436. int segment[2]; /* segment number, start from 0 for first */
  437. double distance[2];
  438. double x, y, z;
  439. } CROSS;
  440. /* Current line in arrays is for some functions like cmp() set by: */
  441. static int current;
  442. static int second; /* line which is not current */
  443. static int a_cross = 0;
  444. static int n_cross;
  445. static CROSS *cross = NULL;
  446. static int *use_cross = NULL;
  447. static void add_cross(int asegment, double adistance, int bsegment,
  448. double bdistance, double x, double y)
  449. {
  450. if (n_cross == a_cross) {
  451. /* Must be space + 1, used later for last line point, do it better */
  452. cross =
  453. (CROSS *) G_realloc((void *)cross,
  454. (a_cross + 101) * sizeof(CROSS));
  455. use_cross =
  456. (int *)G_realloc((void *)use_cross,
  457. (a_cross + 101) * sizeof(int));
  458. a_cross += 100;
  459. }
  460. G_debug(5,
  461. " add new cross: aseg/dist = %d/%f bseg/dist = %d/%f, x = %f y = %f",
  462. asegment, adistance, bsegment, bdistance, x, y);
  463. cross[n_cross].segment[0] = asegment;
  464. cross[n_cross].distance[0] = adistance;
  465. cross[n_cross].segment[1] = bsegment;
  466. cross[n_cross].distance[1] = bdistance;
  467. cross[n_cross].x = x;
  468. cross[n_cross].y = y;
  469. n_cross++;
  470. }
  471. static int cmp_cross(const void *pa, const void *pb)
  472. {
  473. CROSS *p1 = (CROSS *) pa;
  474. CROSS *p2 = (CROSS *) pb;
  475. if (p1->segment[current] < p2->segment[current])
  476. return -1;
  477. if (p1->segment[current] > p2->segment[current])
  478. return 1;
  479. /* the same segment */
  480. if (p1->distance[current] < p2->distance[current])
  481. return -1;
  482. if (p1->distance[current] > p2->distance[current])
  483. return 1;
  484. return 0;
  485. }
  486. static double dist2(double x1, double y1, double x2, double y2)
  487. {
  488. double dx, dy;
  489. dx = x2 - x1;
  490. dy = y2 - y1;
  491. return (dx * dx + dy * dy);
  492. }
  493. #if 0
  494. /* returns 1 if points are identical */
  495. static int ident(double x1, double y1, double x2, double y2, double thresh)
  496. {
  497. double dx, dy;
  498. dx = x2 - x1;
  499. dy = y2 - y1;
  500. if ((dx * dx + dy * dy) <= thresh * thresh)
  501. return 1;
  502. return 0;
  503. }
  504. #endif
  505. /* shared by Vect_line_intersection, Vect_line_check_intersection, cross_seg, find_cross */
  506. static struct line_pnts *APnts, *BPnts;
  507. /* break segments (called by rtree search) */
  508. static int cross_seg(int id, const struct RTree_Rect *rect, void *arg)
  509. {
  510. double x1, y1, z1, x2, y2, z2;
  511. int i, j, ret;
  512. /* !!! segment number for B lines is returned as +1 */
  513. i = *(int *)arg;
  514. j = id - 1;
  515. /* Note: -1 to make up for the +1 when data was inserted */
  516. ret = Vect_segment_intersection(APnts->x[i], APnts->y[i], APnts->z[i],
  517. APnts->x[i + 1], APnts->y[i + 1],
  518. APnts->z[i + 1], BPnts->x[j], BPnts->y[j],
  519. BPnts->z[j], BPnts->x[j + 1],
  520. BPnts->y[j + 1], BPnts->z[j + 1], &x1,
  521. &y1, &z1, &x2, &y2, &z2, 0);
  522. /* add ALL (including end points and duplicates), clean later */
  523. if (ret > 0) {
  524. G_debug(2, " -> %d x %d: intersection type = %d", i, j, ret);
  525. if (ret == 1) { /* one intersection on segment A */
  526. G_debug(3, " in %f, %f ", x1, y1);
  527. add_cross(i, 0.0, j, 0.0, x1, y1);
  528. }
  529. else if (ret == 2 || ret == 3 || ret == 4 || ret == 5) {
  530. /* partial overlap; a broken in one, b broken in one
  531. * or a contains b; a is broken in 2 points (but 1 may be end)
  532. * or b contains a; b is broken in 2 points (but 1 may be end)
  533. * or identical */
  534. G_debug(3, " in %f, %f; %f, %f", x1, y1, x2, y2);
  535. add_cross(i, 0.0, j, 0.0, x1, y1);
  536. add_cross(i, 0.0, j, 0.0, x2, y2);
  537. }
  538. }
  539. return 1; /* keep going */
  540. }
  541. /*!
  542. * \brief Intersect 2 lines.
  543. *
  544. * Creates array of new lines created from original A line, by
  545. * intersection with B line. Points (Points->n_points == 1) are not
  546. * supported.
  547. *
  548. * \param APoints first input line
  549. * \param BPoints second input line
  550. * \param[out] ALines array of new lines created from original A line
  551. * \param[out] BLines array of new lines created from original B line
  552. * \param[out] nalines number of new lines (ALines)
  553. * \param[out] nblines number of new lines (BLines)
  554. * \param with_z 3D, not supported!
  555. *
  556. * \return 0 no intersection
  557. * \return 1 intersection found
  558. */
  559. int
  560. Vect_line_intersection(struct line_pnts *APoints,
  561. struct line_pnts *BPoints,
  562. struct bound_box *ABox,
  563. struct bound_box *BBox,
  564. struct line_pnts ***ALines,
  565. struct line_pnts ***BLines,
  566. int *nalines, int *nblines, int with_z)
  567. {
  568. int i, j, k, l, last_seg, seg, last;
  569. int n_alive_cross;
  570. double dist, curdist, last_x, last_y, last_z;
  571. double x, y, rethresh;
  572. struct line_pnts **XLines, *Points;
  573. struct RTree *MyRTree;
  574. struct line_pnts *Points1, *Points2; /* first, second points */
  575. int seg1, seg2, vert1, vert2;
  576. static struct RTree_Rect rect;
  577. static int rect_init = 0;
  578. struct bound_box box, abbox;
  579. if (debug_level == -1) {
  580. const char *dstr = G_getenv_nofatal("DEBUG");
  581. if (dstr != NULL)
  582. debug_level = atoi(dstr);
  583. else
  584. debug_level = 0;
  585. }
  586. if (!rect_init) {
  587. rect.boundary = G_malloc(6 * sizeof(RectReal));
  588. rect_init = 6;
  589. }
  590. n_cross = 0;
  591. rethresh = 0.000001; /* TODO */
  592. APnts = APoints;
  593. BPnts = BPoints;
  594. /* RE (representation error).
  595. * RE thresh above is nonsense of course, the RE threshold should be based on
  596. * number of significant digits for double (IEEE-754) which is 15 or 16 and exponent.
  597. * The number above is in fact not required threshold, and will not work
  598. * for example: equator length is 40.075,695 km (8 digits), units are m (+3)
  599. * and we want precision in mm (+ 3) = 14 -> minimum rethresh may be around 0.001
  600. * ?Maybe all nonsense?
  601. * Use rounding error of the unit in the least place ?
  602. * max of fabs(x), fabs(y)
  603. * rethresh = pow(2, log2(max) - 53) */
  604. /* Warning: This function is also used to intersect the line by itself i.e. APoints and
  605. * BPoints are identical. I am not sure if it is clever, but it seems to work, but
  606. * we have to keep this in mind and handle some special cases (maybe) */
  607. /* TODO: 3D, RE threshold, GV_POINTS (line x point) */
  608. /* Take each segment from A and intersect by each segment from B.
  609. *
  610. * All intersections are found first and saved to array, then sorted by a distance along the line,
  611. * and then the line is split to pieces.
  612. *
  613. * Note: If segments are collinear, check if previous/next segments are also collinear,
  614. * in that case do not break:
  615. * +----------+
  616. * +----+-----+ etc.
  617. * doesn't need to be broken
  618. *
  619. * Note: If 2 adjacent segments of line B have common vertex exactly (or within thresh) on line A,
  620. * intersection points for these B segments may differ due to RE:
  621. * ------------ a ----+--+---- ----+--+----
  622. * /\ => / \ or maybe \/
  623. * b0 / \ b1 / \ even: /\
  624. *
  625. * -> solution: snap all breaks to nearest vertices first within RE threshold
  626. *
  627. * Question: Snap all breaks to each other within RE threshold?
  628. *
  629. * Note: If a break is snapped to end point or two breaks are snapped to the same vertex
  630. * resulting new line is degenerated => before line is added to array, it must be checked
  631. * if line is not degenerated
  632. *
  633. * Note: to snap to vertices is important for cases where line A is broken by B and C line
  634. * at the same point:
  635. * \ / b no snap \ /
  636. * \/ could ----+--+----
  637. * ------ a result
  638. * /\ in ?: /\
  639. * / \ c / \
  640. *
  641. * Note: once we snap breaks to vertices, we have to do that for both lines A and B in the same way
  642. * and because we cannot be sure that A childrens will not change a bit by break(s)
  643. * we have to break both A and B at once i.e. in one Vect_line_intersection () call.
  644. */
  645. /* Spatial index: lines may be very long (thousands of segments) and check each segment
  646. * with each from second line takes a long time (n*m). Because of that, spatial index
  647. * is build first for the second line and segments from the first line are broken by segments
  648. * in bound box */
  649. if (!Vect_box_overlap(ABox, BBox)) {
  650. *nalines = 0;
  651. *nblines = 0;
  652. return 0;
  653. }
  654. abbox = *BBox;
  655. if (abbox.N > ABox->N)
  656. abbox.N = ABox->N;
  657. if (abbox.S < ABox->S)
  658. abbox.S = ABox->S;
  659. if (abbox.E > ABox->E)
  660. abbox.E = ABox->E;
  661. if (abbox.W < ABox->W)
  662. abbox.W = ABox->W;
  663. if (abbox.T > ABox->T)
  664. abbox.T = ABox->T;
  665. if (abbox.B < ABox->B)
  666. abbox.B = ABox->B;
  667. abbox.N += rethresh;
  668. abbox.S -= rethresh;
  669. abbox.E += rethresh;
  670. abbox.W -= rethresh;
  671. abbox.T += rethresh;
  672. abbox.B -= rethresh;
  673. /* Create rtree for B line */
  674. MyRTree = RTreeCreateTree(-1, 0, 2);
  675. RTreeSetOverflow(MyRTree, 0);
  676. for (i = 0; i < BPoints->n_points - 1; i++) {
  677. if (BPoints->x[i] <= BPoints->x[i + 1]) {
  678. rect.boundary[0] = BPoints->x[i];
  679. rect.boundary[3] = BPoints->x[i + 1];
  680. }
  681. else {
  682. rect.boundary[0] = BPoints->x[i + 1];
  683. rect.boundary[3] = BPoints->x[i];
  684. }
  685. if (BPoints->y[i] <= BPoints->y[i + 1]) {
  686. rect.boundary[1] = BPoints->y[i];
  687. rect.boundary[4] = BPoints->y[i + 1];
  688. }
  689. else {
  690. rect.boundary[1] = BPoints->y[i + 1];
  691. rect.boundary[4] = BPoints->y[i];
  692. }
  693. if (BPoints->z[i] <= BPoints->z[i + 1]) {
  694. rect.boundary[2] = BPoints->z[i];
  695. rect.boundary[5] = BPoints->z[i + 1];
  696. }
  697. else {
  698. rect.boundary[2] = BPoints->z[i + 1];
  699. rect.boundary[5] = BPoints->z[i];
  700. }
  701. box.W = rect.boundary[0] - rethresh;
  702. box.S = rect.boundary[1] - rethresh;
  703. box.B = rect.boundary[2] - rethresh;
  704. box.E = rect.boundary[3] + rethresh;
  705. box.N = rect.boundary[4] + rethresh;
  706. box.T = rect.boundary[5] + rethresh;
  707. if (Vect_box_overlap(&abbox, &box)) {
  708. RTreeInsertRect(&rect, i + 1, MyRTree); /* B line segment numbers in rtree start from 1 */
  709. }
  710. }
  711. /* Break segments in A by segments in B */
  712. for (i = 0; i < APoints->n_points - 1; i++) {
  713. if (APoints->x[i] <= APoints->x[i + 1]) {
  714. rect.boundary[0] = APoints->x[i];
  715. rect.boundary[3] = APoints->x[i + 1];
  716. }
  717. else {
  718. rect.boundary[0] = APoints->x[i + 1];
  719. rect.boundary[3] = APoints->x[i];
  720. }
  721. if (APoints->y[i] <= APoints->y[i + 1]) {
  722. rect.boundary[1] = APoints->y[i];
  723. rect.boundary[4] = APoints->y[i + 1];
  724. }
  725. else {
  726. rect.boundary[1] = APoints->y[i + 1];
  727. rect.boundary[4] = APoints->y[i];
  728. }
  729. if (APoints->z[i] <= APoints->z[i + 1]) {
  730. rect.boundary[2] = APoints->z[i];
  731. rect.boundary[5] = APoints->z[i + 1];
  732. }
  733. else {
  734. rect.boundary[2] = APoints->z[i + 1];
  735. rect.boundary[5] = APoints->z[i];
  736. }
  737. box.W = rect.boundary[0] - rethresh;
  738. box.S = rect.boundary[1] - rethresh;
  739. box.B = rect.boundary[2] - rethresh;
  740. box.E = rect.boundary[3] + rethresh;
  741. box.N = rect.boundary[4] + rethresh;
  742. box.T = rect.boundary[5] + rethresh;
  743. if (Vect_box_overlap(&abbox, &box)) {
  744. j = RTreeSearch(MyRTree, &rect, cross_seg, &i); /* A segment number from 0 */
  745. }
  746. }
  747. /* Free RTree */
  748. RTreeDestroyTree(MyRTree);
  749. G_debug(2, "n_cross = %d", n_cross);
  750. /* Lines do not cross each other */
  751. if (n_cross == 0) {
  752. *nalines = 0;
  753. *nblines = 0;
  754. return 0;
  755. }
  756. /* Snap breaks to nearest vertices within RE threshold */
  757. /* Calculate distances along segments */
  758. for (i = 0; i < n_cross; i++) {
  759. /* 1. of A seg */
  760. seg = cross[i].segment[0];
  761. curdist =
  762. dist2(cross[i].x, cross[i].y, APoints->x[seg], APoints->y[seg]);
  763. x = APoints->x[seg];
  764. y = APoints->y[seg];
  765. cross[i].distance[0] = curdist;
  766. /* 2. of A seg */
  767. dist =
  768. dist2(cross[i].x, cross[i].y, APoints->x[seg + 1],
  769. APoints->y[seg + 1]);
  770. if (dist < curdist) {
  771. curdist = dist;
  772. x = APoints->x[seg + 1];
  773. y = APoints->y[seg + 1];
  774. }
  775. /* 1. of B seg */
  776. seg = cross[i].segment[1];
  777. dist =
  778. dist2(cross[i].x, cross[i].y, BPoints->x[seg], BPoints->y[seg]);
  779. cross[i].distance[1] = dist;
  780. if (dist < curdist) {
  781. curdist = dist;
  782. x = BPoints->x[seg];
  783. y = BPoints->y[seg];
  784. }
  785. /* 2. of B seg */
  786. dist = dist2(cross[i].x, cross[i].y, BPoints->x[seg + 1], BPoints->y[seg + 1]);
  787. if (dist < curdist) {
  788. curdist = dist;
  789. x = BPoints->x[seg + 1];
  790. y = BPoints->y[seg + 1];
  791. }
  792. if (curdist < rethresh * rethresh) {
  793. cross[i].x = x;
  794. cross[i].y = y;
  795. /* Update distances along segments */
  796. seg = cross[i].segment[0];
  797. cross[i].distance[0] =
  798. dist2(APoints->x[seg], APoints->y[seg], cross[i].x, cross[i].y);
  799. seg = cross[i].segment[1];
  800. cross[i].distance[1] =
  801. dist2(BPoints->x[seg], BPoints->y[seg], cross[i].x, cross[i].y);
  802. }
  803. }
  804. /* l = 1 ~ line A, l = 2 ~ line B */
  805. for (l = 1; l < 3; l++) {
  806. for (i = 0; i < n_cross; i++)
  807. use_cross[i] = 1;
  808. /* Create array of lines */
  809. XLines = G_malloc((n_cross + 1) * sizeof(struct line_pnts *));
  810. if (l == 1) {
  811. G_debug(2, "Clean and create array for line A");
  812. Points = APoints;
  813. Points1 = APoints;
  814. Points2 = BPoints;
  815. current = 0;
  816. second = 1;
  817. }
  818. else {
  819. G_debug(2, "Clean and create array for line B");
  820. Points = BPoints;
  821. Points1 = BPoints;
  822. Points2 = APoints;
  823. current = 1;
  824. second = 0;
  825. }
  826. /* Sort points along lines */
  827. qsort((void *)cross, sizeof(char) * n_cross, sizeof(CROSS),
  828. cmp_cross);
  829. /* Print all (raw) breaks */
  830. /* avoid loop when not debugging */
  831. if (debug_level > 2) {
  832. for (i = 0; i < n_cross; i++) {
  833. G_debug(3,
  834. " cross = %d seg1/dist1 = %d/%f seg2/dist2 = %d/%f x = %f y = %f",
  835. i, cross[i].segment[current],
  836. sqrt(cross[i].distance[current]),
  837. cross[i].segment[second], sqrt(cross[i].distance[second]),
  838. cross[i].x, cross[i].y);
  839. }
  840. }
  841. /* Remove breaks on first/last line vertices */
  842. for (i = 0; i < n_cross; i++) {
  843. if (use_cross[i] == 1) {
  844. j = Points1->n_points - 1;
  845. /* Note: */
  846. if ((cross[i].segment[current] == 0 &&
  847. cross[i].x == Points1->x[0] &&
  848. cross[i].y == Points1->y[0]) ||
  849. (cross[i].segment[current] == j - 1 &&
  850. cross[i].x == Points1->x[j] &&
  851. cross[i].y == Points1->y[j])) {
  852. use_cross[i] = 0; /* first/last */
  853. G_debug(3, "cross %d deleted (first/last point)", i);
  854. }
  855. }
  856. }
  857. /* Remove breaks with collinear previous and next segments on 1 and 2 */
  858. /* Note: breaks with collinear previous and nex must be remove duplicates,
  859. * otherwise some cross may be lost. Example (+ is vertex):
  860. * B first cross intersections: A/B segment:
  861. * | 0/0, 0/1, 1/0, 1/1 - collinear previous and next
  862. * AB -----+----+--- A 0/4, 0/5, 1/4, 1/5 - OK
  863. * \___|
  864. * B
  865. * This should not inluence that break is always on first segment, see below (I hope)
  866. */
  867. /* TODO: this doesn't find identical with breaks on revious/next */
  868. for (i = 0; i < n_cross; i++) {
  869. if (use_cross[i] == 0)
  870. continue;
  871. G_debug(3, " is %d between colinear?", i);
  872. seg1 = cross[i].segment[current];
  873. seg2 = cross[i].segment[second];
  874. /* Is it vertex on 1, which? */
  875. if (cross[i].x == Points1->x[seg1] &&
  876. cross[i].y == Points1->y[seg1]) {
  877. vert1 = seg1;
  878. }
  879. else if (cross[i].x == Points1->x[seg1 + 1] &&
  880. cross[i].y == Points1->y[seg1 + 1]) {
  881. vert1 = seg1 + 1;
  882. }
  883. else {
  884. G_debug(3, " -> is not vertex on 1. line");
  885. continue;
  886. }
  887. /* Is it vertex on 2, which? */
  888. /* For 1. line it is easy, because breaks on vertex are always at end vertex
  889. * for 2. line we need to find which vertex is on break if any (vert2 starts from 0) */
  890. if (cross[i].x == Points2->x[seg2] &&
  891. cross[i].y == Points2->y[seg2]) {
  892. vert2 = seg2;
  893. }
  894. else if (cross[i].x == Points2->x[seg2 + 1] &&
  895. cross[i].y == Points2->y[seg2 + 1]) {
  896. vert2 = seg2 + 1;
  897. }
  898. else {
  899. G_debug(3, " -> is not vertex on 2. line");
  900. continue;
  901. }
  902. G_debug(3, " seg1/vert1 = %d/%d seg2/ver2 = %d/%d", seg1,
  903. vert1, seg2, vert2);
  904. /* Check if the second vertex is not first/last */
  905. if (vert2 == 0 || vert2 == Points2->n_points - 1) {
  906. G_debug(3, " -> vertex 2 (%d) is first/last", vert2);
  907. continue;
  908. }
  909. /* Are there first vertices of this segment identical */
  910. if (!((Points1->x[vert1 - 1] == Points2->x[vert2 - 1] &&
  911. Points1->y[vert1 - 1] == Points2->y[vert2 - 1] &&
  912. Points1->x[vert1 + 1] == Points2->x[vert2 + 1] &&
  913. Points1->y[vert1 + 1] == Points2->y[vert2 + 1]) ||
  914. (Points1->x[vert1 - 1] == Points2->x[vert2 + 1] &&
  915. Points1->y[vert1 - 1] == Points2->y[vert2 + 1] &&
  916. Points1->x[vert1 + 1] == Points2->x[vert2 - 1] &&
  917. Points1->y[vert1 + 1] == Points2->y[vert2 - 1])
  918. )
  919. ) {
  920. G_debug(3, " -> previous/next are not identical");
  921. continue;
  922. }
  923. use_cross[i] = 0;
  924. G_debug(3, " -> collinear -> remove");
  925. }
  926. /* Remove duplicates, i.e. merge all identical breaks to one.
  927. * We must be careful because two points with identical coordinates may be distant if measured along
  928. * the line:
  929. * | Segments b0 and b1 overlap, b0 runs up, b1 down.
  930. * | Two inersections may be merged for a, because they are identical,
  931. * -----+---- a but cannot be merged for b, because both b0 and b1 must be broken.
  932. * | I.e. Breaks on b have identical coordinates, but there are not identical
  933. * b0 | b1 if measured along line b.
  934. *
  935. * -> Breaks may be merged as identical if lay on the same segment, or on vertex connecting
  936. * 2 adjacent segments the points lay on
  937. *
  938. * Note: if duplicate is on a vertex, the break is removed from next segment =>
  939. * break on vertex is always on first segment of this vertex (used below)
  940. */
  941. last = -1;
  942. for (i = 0; i < n_cross; i++) {
  943. if (use_cross[i] == 0)
  944. continue;
  945. if (last == -1) { /* set first alive */
  946. last = i;
  947. continue;
  948. }
  949. seg = cross[i].segment[current];
  950. /* compare with last */
  951. G_debug(3, " duplicate ?: cross = %d seg = %d dist = %f", i,
  952. cross[i].segment[current], cross[i].distance[current]);
  953. if ((cross[i].segment[current] == cross[last].segment[current] &&
  954. cross[i].distance[current] == cross[last].distance[current])
  955. || (cross[i].segment[current] ==
  956. cross[last].segment[current] + 1 &&
  957. cross[i].distance[current] == 0 &&
  958. cross[i].x == cross[last].x &&
  959. cross[i].y == cross[last].y)) {
  960. G_debug(3, " cross %d identical to last -> removed", i);
  961. use_cross[i] = 0; /* identical */
  962. }
  963. else {
  964. last = i;
  965. }
  966. }
  967. /* Create array of new lines */
  968. /* Count alive crosses */
  969. n_alive_cross = 0;
  970. G_debug(3, " alive crosses:");
  971. for (i = 0; i < n_cross; i++) {
  972. if (use_cross[i] == 1) {
  973. G_debug(3, " %d", i);
  974. n_alive_cross++;
  975. }
  976. }
  977. k = 0;
  978. if (n_alive_cross > 0) {
  979. /* Add last line point at the end of cross array (cross alley) */
  980. use_cross[n_cross] = 1;
  981. j = Points->n_points - 1;
  982. cross[n_cross].x = Points->x[j];
  983. cross[n_cross].y = Points->y[j];
  984. cross[n_cross].segment[current] = Points->n_points - 2;
  985. last_seg = 0;
  986. last_x = Points->x[0];
  987. last_y = Points->y[0];
  988. last_z = Points->z[0];
  989. /* Go through all cross (+last line point) and create for each new line
  990. * starting at last_* and ending at cross (last point) */
  991. for (i = 0; i <= n_cross; i++) { /* i.e. n_cross + 1 new lines */
  992. seg = cross[i].segment[current];
  993. G_debug(2, "%d seg = %d dist = %f", i, seg,
  994. cross[i].distance[current]);
  995. if (use_cross[i] == 0) {
  996. G_debug(3, " removed -> next");
  997. continue;
  998. }
  999. G_debug(2, " New line:");
  1000. XLines[k] = Vect_new_line_struct();
  1001. /* add last intersection or first point first */
  1002. Vect_append_point(XLines[k], last_x, last_y, last_z);
  1003. G_debug(2, " append last vert: %f %f", last_x, last_y);
  1004. /* add first points of segments between last and current seg */
  1005. for (j = last_seg + 1; j <= seg; j++) {
  1006. G_debug(2, " segment j = %d", j);
  1007. /* skipp vertex identical to last break */
  1008. if ((j == last_seg + 1) && Points->x[j] == last_x &&
  1009. Points->y[j] == last_y) {
  1010. G_debug(2, " -> skip (identical to last break)");
  1011. continue;
  1012. }
  1013. Vect_append_point(XLines[k], Points->x[j], Points->y[j],
  1014. Points->z[j]);
  1015. G_debug(2, " append first of seg: %f %f", Points->x[j],
  1016. Points->y[j]);
  1017. }
  1018. last_seg = seg;
  1019. last_x = cross[i].x;
  1020. last_y = cross[i].y;
  1021. last_z = 0;
  1022. /* calculate last_z */
  1023. if (Points->z[last_seg] == Points->z[last_seg + 1]) {
  1024. last_z = Points->z[last_seg + 1];
  1025. }
  1026. else if (last_x == Points->x[last_seg] &&
  1027. last_y == Points->y[last_seg]) {
  1028. last_z = Points->z[last_seg];
  1029. }
  1030. else if (last_x == Points->x[last_seg + 1] &&
  1031. last_y == Points->y[last_seg + 1]) {
  1032. last_z = Points->z[last_seg + 1];
  1033. }
  1034. else {
  1035. dist = dist2(Points->x[last_seg],
  1036. Points->x[last_seg + 1],
  1037. Points->y[last_seg],
  1038. Points->y[last_seg + 1]);
  1039. last_z = (Points->z[last_seg] * sqrt(cross[i].distance[current]) +
  1040. Points->z[last_seg + 1] * (sqrt(dist) - sqrt(cross[i].distance[current]))) /
  1041. sqrt(dist);
  1042. }
  1043. /* add current cross or end point */
  1044. Vect_append_point(XLines[k], cross[i].x, cross[i].y, last_z);
  1045. G_debug(2, " append cross / last point: %f %f", cross[i].x,
  1046. cross[i].y);
  1047. /* Check if line is degenerate */
  1048. if (dig_line_degenerate(XLines[k]) > 0) {
  1049. G_debug(2, " line is degenerate -> skipped");
  1050. Vect_destroy_line_struct(XLines[k]);
  1051. }
  1052. else {
  1053. k++;
  1054. }
  1055. }
  1056. }
  1057. if (l == 1) {
  1058. *nalines = k;
  1059. *ALines = XLines;
  1060. }
  1061. else {
  1062. *nblines = k;
  1063. *BLines = XLines;
  1064. }
  1065. }
  1066. /* clean up */
  1067. return 1;
  1068. }
  1069. static struct line_pnts *APnts, *BPnts, *IPnts;
  1070. static int cross_found; /* set by find_cross() */
  1071. /* break segments (called by rtree search) */
  1072. static int find_cross(int id, const struct RTree_Rect *rect, void *arg)
  1073. {
  1074. double x1, y1, z1, x2, y2, z2;
  1075. int i, j, ret;
  1076. /* !!! segment number for B lines is returned as +1 */
  1077. i = *(int *)arg;
  1078. j = id - 1;
  1079. /* Note: -1 to make up for the +1 when data was inserted */
  1080. ret = Vect_segment_intersection(APnts->x[i], APnts->y[i], APnts->z[i],
  1081. APnts->x[i + 1], APnts->y[i + 1],
  1082. APnts->z[i + 1], BPnts->x[j], BPnts->y[j],
  1083. BPnts->z[j], BPnts->x[j + 1],
  1084. BPnts->y[j + 1], BPnts->z[j + 1], &x1,
  1085. &y1, &z1, &x2, &y2, &z2, 0);
  1086. switch (ret) {
  1087. case 0:
  1088. case 5:
  1089. break;
  1090. case 1:
  1091. if (0 > Vect_copy_xyz_to_pnts(IPnts, &x1, &y1, &z1, 1))
  1092. G_warning(_("Error while adding point to array. Out of memory"));
  1093. break;
  1094. case 2:
  1095. case 3:
  1096. case 4:
  1097. if (0 > Vect_copy_xyz_to_pnts(IPnts, &x1, &y1, &z1, 1))
  1098. G_warning(_("Error while adding point to array. Out of memory"));
  1099. if (0 > Vect_copy_xyz_to_pnts(IPnts, &x2, &y2, &z2, 1))
  1100. G_warning(_("Error while adding point to array. Out of memory"));
  1101. break;
  1102. }
  1103. /* add ALL (including end points and duplicates), clean later */
  1104. if (ret > 0) {
  1105. cross_found = 1;
  1106. return 0;
  1107. }
  1108. return 1; /* keep going */
  1109. }
  1110. /*!
  1111. * \brief Check if 2 lines intersect.
  1112. *
  1113. * Points (Points->n_points == 1) are also supported.
  1114. *
  1115. * \param APoints first input line
  1116. * \param BPoints second input line
  1117. * \param with_z 3D, not supported (only if one or both are points)!
  1118. *
  1119. * \return 0 no intersection
  1120. * \return 1 intersection found
  1121. */
  1122. int
  1123. Vect_line_check_intersection(struct line_pnts *APoints,
  1124. struct line_pnts *BPoints, int with_z)
  1125. {
  1126. int i;
  1127. double dist, rethresh;
  1128. struct RTree *MyRTree;
  1129. static struct RTree_Rect rect;
  1130. static int rect_init = 0;
  1131. if (!rect_init) {
  1132. rect.boundary = G_malloc(6 * sizeof(RectReal));
  1133. rect_init = 6;
  1134. }
  1135. rethresh = 0.000001; /* TODO */
  1136. APnts = APoints;
  1137. BPnts = BPoints;
  1138. /* TODO: 3D, RE (representation error) threshold, GV_POINTS (line x point) */
  1139. if (!IPnts)
  1140. IPnts = Vect_new_line_struct();
  1141. Vect_reset_line(IPnts);
  1142. /* If one or both are point (Points->n_points == 1) */
  1143. if (APoints->n_points == 1 && BPoints->n_points == 1) {
  1144. if (APoints->x[0] == BPoints->x[0] && APoints->y[0] == BPoints->y[0]) {
  1145. if (!with_z) {
  1146. if (0 >
  1147. Vect_copy_xyz_to_pnts(IPnts, &APoints->x[0],
  1148. &APoints->y[0], NULL, 1))
  1149. G_warning(_("Error while adding point to array. Out of memory"));
  1150. return 1;
  1151. }
  1152. else {
  1153. if (APoints->z[0] == BPoints->z[0]) {
  1154. if (0 >
  1155. Vect_copy_xyz_to_pnts(IPnts, &APoints->x[0],
  1156. &APoints->y[0], &APoints->z[0],
  1157. 1))
  1158. G_warning(_("Error while adding point to array. Out of memory"));
  1159. return 1;
  1160. }
  1161. else
  1162. return 0;
  1163. }
  1164. }
  1165. else {
  1166. return 0;
  1167. }
  1168. }
  1169. if (APoints->n_points == 1) {
  1170. Vect_line_distance(BPoints, APoints->x[0], APoints->y[0],
  1171. APoints->z[0], with_z, NULL, NULL, NULL, &dist,
  1172. NULL, NULL);
  1173. if (dist <= rethresh) {
  1174. if (0 >
  1175. Vect_copy_xyz_to_pnts(IPnts, &APoints->x[0], &APoints->y[0],
  1176. &APoints->z[0], 1))
  1177. G_warning(_("Error while adding point to array. Out of memory"));
  1178. return 1;
  1179. }
  1180. else {
  1181. return 0;
  1182. }
  1183. }
  1184. if (BPoints->n_points == 1) {
  1185. Vect_line_distance(APoints, BPoints->x[0], BPoints->y[0],
  1186. BPoints->z[0], with_z, NULL, NULL, NULL, &dist,
  1187. NULL, NULL);
  1188. if (dist <= rethresh) {
  1189. if (0 >
  1190. Vect_copy_xyz_to_pnts(IPnts, &BPoints->x[0], &BPoints->y[0],
  1191. &BPoints->z[0], 1))
  1192. G_warning(_("Error while adding point to array. Out of memory"));
  1193. return 1;
  1194. }
  1195. else
  1196. return 0;
  1197. }
  1198. /* Take each segment from A and find if intersects any segment from B. */
  1199. /* Spatial index: lines may be very long (thousands of segments) and check each segment
  1200. * with each from second line takes a long time (n*m). Because of that, spatial index
  1201. * is build first for the second line and segments from the first line are broken by segments
  1202. * in bound box */
  1203. /* Create rtree for B line */
  1204. MyRTree = RTreeCreateTree(-1, 0, 2);
  1205. RTreeSetOverflow(MyRTree, 0);
  1206. for (i = 0; i < BPoints->n_points - 1; i++) {
  1207. if (BPoints->x[i] <= BPoints->x[i + 1]) {
  1208. rect.boundary[0] = BPoints->x[i];
  1209. rect.boundary[3] = BPoints->x[i + 1];
  1210. }
  1211. else {
  1212. rect.boundary[0] = BPoints->x[i + 1];
  1213. rect.boundary[3] = BPoints->x[i];
  1214. }
  1215. if (BPoints->y[i] <= BPoints->y[i + 1]) {
  1216. rect.boundary[1] = BPoints->y[i];
  1217. rect.boundary[4] = BPoints->y[i + 1];
  1218. }
  1219. else {
  1220. rect.boundary[1] = BPoints->y[i + 1];
  1221. rect.boundary[4] = BPoints->y[i];
  1222. }
  1223. if (BPoints->z[i] <= BPoints->z[i + 1]) {
  1224. rect.boundary[2] = BPoints->z[i];
  1225. rect.boundary[5] = BPoints->z[i + 1];
  1226. }
  1227. else {
  1228. rect.boundary[2] = BPoints->z[i + 1];
  1229. rect.boundary[5] = BPoints->z[i];
  1230. }
  1231. RTreeInsertRect(&rect, i + 1, MyRTree); /* B line segment numbers in rtree start from 1 */
  1232. }
  1233. /* Find intersection */
  1234. cross_found = 0;
  1235. for (i = 0; i < APoints->n_points - 1; i++) {
  1236. if (APoints->x[i] <= APoints->x[i + 1]) {
  1237. rect.boundary[0] = APoints->x[i];
  1238. rect.boundary[3] = APoints->x[i + 1];
  1239. }
  1240. else {
  1241. rect.boundary[0] = APoints->x[i + 1];
  1242. rect.boundary[3] = APoints->x[i];
  1243. }
  1244. if (APoints->y[i] <= APoints->y[i + 1]) {
  1245. rect.boundary[1] = APoints->y[i];
  1246. rect.boundary[4] = APoints->y[i + 1];
  1247. }
  1248. else {
  1249. rect.boundary[1] = APoints->y[i + 1];
  1250. rect.boundary[4] = APoints->y[i];
  1251. }
  1252. if (APoints->z[i] <= APoints->z[i + 1]) {
  1253. rect.boundary[2] = APoints->z[i];
  1254. rect.boundary[5] = APoints->z[i + 1];
  1255. }
  1256. else {
  1257. rect.boundary[2] = APoints->z[i + 1];
  1258. rect.boundary[5] = APoints->z[i];
  1259. }
  1260. RTreeSearch(MyRTree, &rect, find_cross, &i); /* A segment number from 0 */
  1261. if (cross_found) {
  1262. break;
  1263. }
  1264. }
  1265. /* Free RTree */
  1266. RTreeDestroyTree(MyRTree);
  1267. return cross_found;
  1268. }
  1269. /*!
  1270. * \brief Get 2 lines intersection points.
  1271. *
  1272. * A wrapper around Vect_line_check_intersection() function.
  1273. *
  1274. * \param APoints first input line
  1275. * \param BPoints second input line
  1276. * \param[out] IPoints output with intersection points
  1277. * \param with_z 3D, not supported (only if one or both are points)!
  1278. *
  1279. * \return 0 no intersection
  1280. * \return 1 intersection found
  1281. */
  1282. int
  1283. Vect_line_get_intersections(struct line_pnts *APoints,
  1284. struct line_pnts *BPoints,
  1285. struct line_pnts *IPoints, int with_z)
  1286. {
  1287. int ret;
  1288. IPnts = IPoints;
  1289. ret = Vect_line_check_intersection(APoints, BPoints, with_z);
  1290. return ret;
  1291. }