gsdrape.c 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373
  1. /*!
  2. \file lib/ogsf/gsdrape.c
  3. \brief OGSF library - functions to intersect line segments with edges of surface polygons
  4. GRASS OpenGL gsurf OGSF Library
  5. For efficiency, intersections are found without respect to which
  6. specific triangle edge is intersected, but on a broader sense with
  7. the horizontal, vertical, and diagonal seams in the grid, then
  8. the intersections are ordered. If quadstrips are used for drawing
  9. rather than tmesh, triangulation is not consistant; for diagonal
  10. intersections, the proper diagonal to intersect would need to be
  11. determined according to the algorithm used by qstrip (look at nearby
  12. normals). It may be faster to go ahead and find the intersections
  13. with the other diagonals using the same methods, then at sorting
  14. time determine which diagonal array to look at for each quad.
  15. It would also require a mechanism for throwing out unused intersections
  16. with the diagonals during the ordering phase.
  17. Do intersections in 2D, fill line structure with 3D pts (maybe calling
  18. routine will cache for redrawing). Get Z value by using linear interp
  19. between corners.
  20. - check for easy cases:
  21. - single point
  22. - colinear with horizontal or vertical edges
  23. - colinear with diagonal edges of triangles
  24. - calculate three arrays of ordered intersections:
  25. - with vertical edges
  26. - with horizontal edges
  27. - with diagonal edges and interpolate Z, using simple linear interpolation.
  28. - eliminate duplicate intersections (need only compare one coord for each)
  29. - build ordered set of points.
  30. Return static pointer to 3D set of points. Max number of intersections
  31. will be rows + cols + diags, so should allocate this number to initialize.
  32. Let calling routine worry about copying points for caching.
  33. (C) 1999-2008 by the GRASS Development Team
  34. This program is free software under the
  35. GNU General Public License (>=v2).
  36. Read the file COPYING that comes with GRASS
  37. for details.
  38. \author Bill Brown UI GMS Lab
  39. \author Doxygenized by Martin Landa <landa.martin gmail.com> (May 2008)
  40. */
  41. #include <stdlib.h>
  42. #include <grass/ogsf.h>
  43. #include <grass/glocale.h>
  44. #include "gsget.h"
  45. #include "rowcol.h"
  46. #include "math.h"
  47. #define DONT_INTERSECT 0
  48. #define DO_INTERSECT 1
  49. #define COLLINEAR 2
  50. #define LERP(a,l,h) ((l)+(((h)-(l))*(a)))
  51. #define EQUAL(a,b) (fabs((a)-(b))<EPSILON)
  52. #define ISNODE(p,res) (fmod((double)p,(double)res)<EPSILON)
  53. #define SAME_SIGNS( a, b ) \
  54. ((a >= 0 && b >= 0) || (a < 0 && b < 0))
  55. static int drape_line_init(int, int);
  56. static Point3 *_gsdrape_get_segments(geosurf *, float *, float *, int *);
  57. static float dist_squared_2d(float *, float *);
  58. /* array of points to be returned */
  59. static Point3 *I3d;
  60. /* make dependent on resolution? */
  61. static float EPSILON = 0.000001;
  62. /*vertical, horizontal, & diagonal intersections */
  63. static Point3 *Vi, *Hi, *Di;
  64. static typbuff *Ebuf; /* elevation buffer */
  65. static int Flat;
  66. /*!
  67. \brief Initizalize
  68. \param rows number of rows
  69. \param cols number of columns
  70. \return -1 on failure
  71. \return 1 on success
  72. */
  73. static int drape_line_init(int rows, int cols)
  74. {
  75. /* use G_calloc() [-> G_fatal_error] instead of calloc ? */
  76. if (NULL == (I3d = (Point3 *) calloc(2 * (rows + cols), sizeof(Point3)))) {
  77. return (-1);
  78. }
  79. if (NULL == (Vi = (Point3 *) calloc(cols, sizeof(Point3)))) {
  80. G_free(I3d);
  81. return (-1);
  82. }
  83. if (NULL == (Hi = (Point3 *) calloc(rows, sizeof(Point3)))) {
  84. G_free(I3d);
  85. G_free(Vi);
  86. return (-1);
  87. }
  88. if (NULL == (Di = (Point3 *) calloc(rows + cols, sizeof(Point3)))) {
  89. G_free(I3d);
  90. G_free(Vi);
  91. G_free(Hi);
  92. return (-1);
  93. }
  94. return (1);
  95. }
  96. /*!
  97. \brief Get segments
  98. \param gs surface (geosurf)
  99. \param bgn begin point
  100. \param end end point
  101. \param num
  102. \return pointer to Point3 struct
  103. */
  104. static Point3 *_gsdrape_get_segments(geosurf * gs, float *bgn, float *end,
  105. int *num)
  106. {
  107. float f[3], l[3];
  108. int vi, hi, di;
  109. float dir[2], yres, xres;
  110. xres = VXRES(gs);
  111. yres = VYRES(gs);
  112. vi = hi = di = 0;
  113. GS_v2dir(bgn, end, dir);
  114. if (dir[X]) {
  115. vi = get_vert_intersects(gs, bgn, end, dir);
  116. }
  117. if (dir[Y]) {
  118. hi = get_horz_intersects(gs, bgn, end, dir);
  119. }
  120. if (!((end[Y] - bgn[Y]) / (end[X] - bgn[X]) == yres / xres)) {
  121. di = get_diag_intersects(gs, bgn, end, dir);
  122. }
  123. interp_first_last(gs, bgn, end, f, l);
  124. *num = order_intersects(gs, f, l, vi, hi, di);
  125. /* fills in return values, eliminates dupes (corners) */
  126. G_debug(5, "_gsdrape_get_segments vi=%d, hi=%d, di=%d, num=%d",
  127. vi, hi, di, *num);
  128. return (I3d);
  129. }
  130. /*!
  131. \brief Calculate 2D distance
  132. \param p1 first point
  133. \param p2 second point
  134. \return distance
  135. */
  136. static float dist_squared_2d(float *p1, float *p2)
  137. {
  138. float dx, dy;
  139. dx = p2[X] - p1[X];
  140. dy = p2[Y] - p1[Y];
  141. return (dx * dx + dy * dy);
  142. }
  143. /*!
  144. \brief ADD
  145. \param gs surface (geosurf)
  146. \return -1 on failure
  147. \return 1 on success
  148. */
  149. int gsdrape_set_surface(geosurf * gs)
  150. {
  151. static int first = 1;
  152. if (first) {
  153. first = 0;
  154. if (0 > drape_line_init(gs->rows, gs->cols)) {
  155. G_warning(_("Unable to process vector map - out of memory"));
  156. Ebuf = NULL;
  157. return (-1);
  158. }
  159. }
  160. Ebuf = gs_get_att_typbuff(gs, ATT_TOPO, 0);
  161. return (1);
  162. }
  163. /*!
  164. \brief Check if segment intersect vector region
  165. Clipping performed:
  166. - bgn and end are replaced so that both points are within viewregion
  167. - if seg intersects
  168. \param gs surface (geosurf)
  169. \param bgn begin point
  170. \param end end point
  171. \return 0 if segment doesn't intersect the viewregion, or intersects only at corner
  172. \return otherwise returns 1
  173. */
  174. int seg_intersect_vregion(geosurf * gs, float *bgn, float *end)
  175. {
  176. float *replace, xl, yb, xr, yt, xi, yi;
  177. int inside = 0;
  178. xl = 0.0;
  179. xr = VCOL2X(gs, VCOLS(gs));
  180. yt = VROW2Y(gs, 0);
  181. yb = VROW2Y(gs, VROWS(gs));
  182. if (in_vregion(gs, bgn)) {
  183. replace = end;
  184. inside++;
  185. }
  186. if (in_vregion(gs, end)) {
  187. replace = bgn;
  188. inside++;
  189. }
  190. if (inside == 2) {
  191. return (1);
  192. }
  193. else if (inside) {
  194. /* one in & one out - replace gets first intersection */
  195. if (segs_intersect
  196. (bgn[X], bgn[Y], end[X], end[Y], xl, yb, xl, yt, &xi, &yi)) {
  197. /* left */
  198. }
  199. else if (segs_intersect
  200. (bgn[X], bgn[Y], end[X], end[Y], xr, yb, xr, yt, &xi, &yi)) {
  201. /* right */
  202. }
  203. else if (segs_intersect
  204. (bgn[X], bgn[Y], end[X], end[Y], xl, yb, xr, yb, &xi, &yi)) {
  205. /* bottom */
  206. }
  207. else if (segs_intersect
  208. (bgn[X], bgn[Y], end[X], end[Y], xl, yt, xr, yt, &xi, &yi)) {
  209. /* top */
  210. }
  211. replace[X] = xi;
  212. replace[Y] = yi;
  213. }
  214. else {
  215. /* both out - find 2 intersects & replace both */
  216. float pt1[2], pt2[2];
  217. replace = pt1;
  218. if (segs_intersect
  219. (bgn[X], bgn[Y], end[X], end[Y], xl, yb, xl, yt, &xi, &yi)) {
  220. replace[X] = xi;
  221. replace[Y] = yi;
  222. replace = pt2;
  223. inside++;
  224. }
  225. if (segs_intersect
  226. (bgn[X], bgn[Y], end[X], end[Y], xr, yb, xr, yt, &xi, &yi)) {
  227. replace[X] = xi;
  228. replace[Y] = yi;
  229. replace = pt2;
  230. inside++;
  231. }
  232. if (inside < 2) {
  233. if (segs_intersect
  234. (bgn[X], bgn[Y], end[X], end[Y], xl, yb, xr, yb, &xi, &yi)) {
  235. replace[X] = xi;
  236. replace[Y] = yi;
  237. replace = pt2;
  238. inside++;
  239. }
  240. }
  241. if (inside < 2) {
  242. if (segs_intersect
  243. (bgn[X], bgn[Y], end[X], end[Y], xl, yt, xr, yt, &xi, &yi)) {
  244. replace[X] = xi;
  245. replace[Y] = yi;
  246. inside++;
  247. }
  248. }
  249. if (inside < 2) {
  250. return (0); /* no intersect or only 1 point on corner */
  251. }
  252. /* compare dist of intersects to bgn - closest replaces bgn */
  253. if (GS_P2distance(bgn, pt1) < GS_P2distance(bgn, pt2)) {
  254. bgn[X] = pt1[X];
  255. bgn[Y] = pt1[Y];
  256. end[X] = pt2[X];
  257. end[Y] = pt2[Y];
  258. }
  259. else {
  260. bgn[X] = pt2[X];
  261. bgn[Y] = pt2[Y];
  262. end[X] = pt1[X];
  263. end[Y] = pt1[Y];
  264. }
  265. }
  266. return (1);
  267. }
  268. /*!
  269. \brief ADD
  270. \param gs surface (geosurf)
  271. \param bgn begin point (x,y)
  272. \param end end point (x,y)
  273. \param num
  274. \return pointer to Point3 struct
  275. */
  276. Point3 *gsdrape_get_segments(geosurf * gs, float *bgn, float *end, int *num)
  277. {
  278. gsdrape_set_surface(gs);
  279. if (!seg_intersect_vregion(gs, bgn, end)) {
  280. *num = 0;
  281. return (NULL);
  282. }
  283. if (CONST_ATT == gs_get_att_src(gs, ATT_TOPO)) {
  284. /* will probably want a force_drape option to get all intersects */
  285. I3d[0][X] = bgn[X];
  286. I3d[0][Y] = bgn[Y];
  287. I3d[0][Z] = gs->att[ATT_TOPO].constant;
  288. I3d[1][X] = end[X];
  289. I3d[1][Y] = end[Y];
  290. I3d[1][Z] = gs->att[ATT_TOPO].constant;
  291. *num = 2;
  292. return (I3d);
  293. }
  294. if (bgn[X] == end[X] && bgn[Y] == end[Y]) {
  295. float f[3], l[3];
  296. interp_first_last(gs, bgn, end, f, l);
  297. GS_v3eq(I3d[0], f);
  298. GS_v3eq(I3d[1], l);
  299. /* CHANGE (*num = 1) to reflect degenerate line ? */
  300. *num = 2;
  301. return (I3d);
  302. }
  303. Flat = 0;
  304. return (_gsdrape_get_segments(gs, bgn, end, num));
  305. }
  306. /*!
  307. \brief Get all segments
  308. \param gs surface (geosurf)
  309. \param bgn begin point
  310. \param end end point
  311. \param num
  312. \return pointer to Point3 struct
  313. */
  314. Point3 *gsdrape_get_allsegments(geosurf * gs, float *bgn, float *end,
  315. int *num)
  316. {
  317. gsdrape_set_surface(gs);
  318. if (!seg_intersect_vregion(gs, bgn, end)) {
  319. *num = 0;
  320. return (NULL);
  321. }
  322. if (bgn[X] == end[X] && bgn[Y] == end[Y]) {
  323. float f[3], l[3];
  324. interp_first_last(gs, bgn, end, f, l);
  325. GS_v3eq(I3d[0], f);
  326. GS_v3eq(I3d[1], l);
  327. *num = 2;
  328. return (I3d);
  329. }
  330. if (CONST_ATT == gs_get_att_src(gs, ATT_TOPO)) {
  331. Flat = 1;
  332. }
  333. else {
  334. Flat = 0;
  335. }
  336. return (_gsdrape_get_segments(gs, bgn, end, num));
  337. }
  338. /*!
  339. \brief ADD
  340. \param gs surface (geosurf)
  341. \param bgn begin point
  342. \param end end point
  343. \param f first
  344. \param l last
  345. */
  346. void interp_first_last(geosurf * gs, float *bgn, float *end, Point3 f,
  347. Point3 l)
  348. {
  349. f[X] = bgn[X];
  350. f[Y] = bgn[Y];
  351. l[X] = end[X];
  352. l[Y] = end[Y];
  353. if (Flat) {
  354. f[Z] = l[Z] = gs->att[ATT_TOPO].constant;
  355. }
  356. else {
  357. viewcell_tri_interp(gs, Ebuf, f, 0);
  358. viewcell_tri_interp(gs, Ebuf, l, 0);
  359. }
  360. return;
  361. }
  362. /*!
  363. \brief ADD
  364. \param gs surface (geosurf)
  365. \param pt
  366. */
  367. int _viewcell_tri_interp(geosurf * gs, Point3 pt)
  368. {
  369. typbuff *buf;
  370. buf = gs_get_att_typbuff(gs, ATT_TOPO, 0);
  371. return (viewcell_tri_interp(gs, buf, pt, 0));
  372. }
  373. /*!
  374. \brief ADD
  375. In gsd_surf, tmesh draws polys like so:
  376. <pre>
  377. --------------
  378. | /|
  379. | / |
  380. | / |
  381. | / |
  382. | / |
  383. | / |
  384. | / |
  385. | / |
  386. | / |
  387. | / |
  388. | / |
  389. |/ |
  390. --------------
  391. </pre>
  392. UNLESS the top right or bottom left point is masked, in which case a
  393. single triangle with the opposite diagonal is drawn. This case is
  394. not yet handled here & should only occur on edges.
  395. pt has X & Y coordinates in it, we interpolate Z here
  396. This could probably be much shorter, but not much faster.
  397. \return 1 if point is in view region
  398. \return otherwise 0 (if masked)
  399. */
  400. int viewcell_tri_interp(geosurf * gs, typbuff * buf, Point3 pt,
  401. int check_mask)
  402. {
  403. Point3 p1, p2, p3;
  404. int offset, drow, dcol, vrow, vcol;
  405. float xmax, ymin, ymax, alpha;
  406. xmax = VCOL2X(gs, VCOLS(gs));
  407. ymax = VROW2Y(gs, 0);
  408. ymin = VROW2Y(gs, VROWS(gs));
  409. if (check_mask) {
  410. if (gs_point_is_masked(gs, pt)) {
  411. return (0);
  412. }
  413. }
  414. if (pt[X] < 0.0 || pt[Y] > ymax) {
  415. /* outside on left or top */
  416. return (0);
  417. }
  418. if (pt[Y] < ymin || pt[X] > xmax) {
  419. /* outside on bottom or right */
  420. return (0);
  421. }
  422. if (CONST_ATT == gs_get_att_src(gs, ATT_TOPO)) {
  423. pt[Z] = gs->att[ATT_TOPO].constant;
  424. return (1);
  425. }
  426. else if (MAP_ATT != gs_get_att_src(gs, ATT_TOPO)) {
  427. return (0);
  428. }
  429. vrow = Y2VROW(gs, pt[Y]);
  430. vcol = X2VCOL(gs, pt[X]);
  431. if (vrow < VROWS(gs) && vcol < VCOLS(gs)) {
  432. /*not on bottom or right edge */
  433. if (pt[X] > 0.0 && pt[Y] < ymax) {
  434. /* not on left or top edge */
  435. p1[X] = VCOL2X(gs, vcol + 1);
  436. p1[Y] = VROW2Y(gs, vrow);
  437. drow = VROW2DROW(gs, vrow);
  438. dcol = VCOL2DCOL(gs, vcol + 1);
  439. offset = DRC2OFF(gs, drow, dcol);
  440. GET_MAPATT(buf, offset, p1[Z]); /* top right */
  441. p2[X] = VCOL2X(gs, vcol);
  442. p2[Y] = VROW2Y(gs, vrow + 1);
  443. drow = VROW2DROW(gs, vrow + 1);
  444. dcol = VCOL2DCOL(gs, vcol);
  445. offset = DRC2OFF(gs, drow, dcol);
  446. GET_MAPATT(buf, offset, p2[Z]); /* bottom left */
  447. if ((pt[X] - p2[X]) / VXRES(gs) > (pt[Y] - p2[Y]) / VYRES(gs)) {
  448. /* lower triangle */
  449. p3[X] = VCOL2X(gs, vcol + 1);
  450. p3[Y] = VROW2Y(gs, vrow + 1);
  451. drow = VROW2DROW(gs, vrow + 1);
  452. dcol = VCOL2DCOL(gs, vcol + 1);
  453. offset = DRC2OFF(gs, drow, dcol);
  454. GET_MAPATT(buf, offset, p3[Z]); /* bottom right */
  455. }
  456. else {
  457. /* upper triangle */
  458. p3[X] = VCOL2X(gs, vcol);
  459. p3[Y] = VROW2Y(gs, vrow);
  460. drow = VROW2DROW(gs, vrow);
  461. dcol = VCOL2DCOL(gs, vcol);
  462. offset = DRC2OFF(gs, drow, dcol);
  463. GET_MAPATT(buf, offset, p3[Z]); /* top left */
  464. }
  465. return (Point_on_plane(p1, p2, p3, pt));
  466. }
  467. else if (pt[X] == 0.0) {
  468. /* on left edge */
  469. if (pt[Y] < ymax) {
  470. vrow = Y2VROW(gs, pt[Y]);
  471. drow = VROW2DROW(gs, vrow);
  472. offset = DRC2OFF(gs, drow, 0);
  473. GET_MAPATT(buf, offset, p1[Z]);
  474. drow = VROW2DROW(gs, vrow + 1);
  475. offset = DRC2OFF(gs, drow, 0);
  476. GET_MAPATT(buf, offset, p2[Z]);
  477. alpha = (VROW2Y(gs, vrow) - pt[Y]) / VYRES(gs);
  478. pt[Z] = LERP(alpha, p1[Z], p2[Z]);
  479. }
  480. else {
  481. /* top left corner */
  482. GET_MAPATT(buf, 0, pt[Z]);
  483. }
  484. return (1);
  485. }
  486. else if (pt[Y] == gs->yrange) {
  487. /* on top edge, not a corner */
  488. vcol = X2VCOL(gs, pt[X]);
  489. dcol = VCOL2DCOL(gs, vcol);
  490. GET_MAPATT(buf, dcol, p1[Z]);
  491. dcol = VCOL2DCOL(gs, vcol + 1);
  492. GET_MAPATT(buf, dcol, p2[Z]);
  493. alpha = (pt[X] - VCOL2X(gs, vcol)) / VXRES(gs);
  494. pt[Z] = LERP(alpha, p1[Z], p2[Z]);
  495. return (1);
  496. }
  497. }
  498. else if (vrow == VROWS(gs)) {
  499. /* on bottom edge */
  500. drow = VROW2DROW(gs, VROWS(gs));
  501. if (pt[X] > 0.0 && pt[X] < xmax) {
  502. /* not a corner */
  503. vcol = X2VCOL(gs, pt[X]);
  504. dcol = VCOL2DCOL(gs, vcol);
  505. offset = DRC2OFF(gs, drow, dcol);
  506. GET_MAPATT(buf, offset, p1[Z]);
  507. dcol = VCOL2DCOL(gs, vcol + 1);
  508. offset = DRC2OFF(gs, drow, dcol);
  509. GET_MAPATT(buf, offset, p2[Z]);
  510. alpha = (pt[X] - VCOL2X(gs, vcol)) / VXRES(gs);
  511. pt[Z] = LERP(alpha, p1[Z], p2[Z]);
  512. return (1);
  513. }
  514. else if (pt[X] == 0.0) {
  515. /* bottom left corner */
  516. offset = DRC2OFF(gs, drow, 0);
  517. GET_MAPATT(buf, offset, pt[Z]);
  518. return (1);
  519. }
  520. else {
  521. /* bottom right corner */
  522. dcol = VCOL2DCOL(gs, VCOLS(gs));
  523. offset = DRC2OFF(gs, drow, dcol);
  524. GET_MAPATT(buf, offset, pt[Z]);
  525. return (1);
  526. }
  527. }
  528. else {
  529. /* on right edge, not bottom corner */
  530. dcol = VCOL2DCOL(gs, VCOLS(gs));
  531. if (pt[Y] < ymax) {
  532. vrow = Y2VROW(gs, pt[Y]);
  533. drow = VROW2DROW(gs, vrow);
  534. offset = DRC2OFF(gs, drow, dcol);
  535. GET_MAPATT(buf, offset, p1[Z]);
  536. drow = VROW2DROW(gs, vrow + 1);
  537. offset = DRC2OFF(gs, drow, dcol);
  538. GET_MAPATT(buf, offset, p2[Z]);
  539. alpha = (VROW2Y(gs, vrow) - pt[Y]) / VYRES(gs);
  540. pt[Z] = LERP(alpha, p1[Z], p2[Z]);
  541. return (1);
  542. }
  543. else {
  544. /* top right corner */
  545. GET_MAPATT(buf, dcol, pt[Z]);
  546. return (1);
  547. }
  548. }
  549. return (0);
  550. }
  551. /*!
  552. \brief ADD
  553. \param gs surface (geosurf)
  554. \return 1
  555. \return 0
  556. */
  557. int in_vregion(geosurf * gs, float *pt)
  558. {
  559. if (pt[X] >= 0.0 && pt[Y] <= gs->yrange) {
  560. if (pt[X] <= VCOL2X(gs, VCOLS(gs))) {
  561. return (pt[Y] >= VROW2Y(gs, VROWS(gs)));
  562. }
  563. }
  564. return (0);
  565. }
  566. /*!
  567. \brief ADD
  568. After all the intersections between the segment and triangle
  569. edges have been found, they are in three lists. (intersections
  570. with vertical, horizontal, and diagonal triangle edges)
  571. Each list is ordered in space from first to last segment points,
  572. but now the lists need to be woven together. This routine
  573. starts with the first point of the segment and then checks the
  574. next point in each list to find the closest, eliminating duplicates
  575. along the way and storing the result in I3d.
  576. \param gs surface (geosurf)
  577. \param first first point
  578. \param last last point
  579. \param vi
  580. \param hi
  581. \param di
  582. \return
  583. */
  584. int order_intersects(geosurf * gs, Point3 first, Point3 last, int vi, int hi,
  585. int di)
  586. {
  587. int num, i, found, cv, ch, cd, cnum;
  588. float dv, dh, dd, big, cpoint[2];
  589. cv = ch = cd = cnum = 0;
  590. num = vi + hi + di;
  591. cpoint[X] = first[X];
  592. cpoint[Y] = first[Y];
  593. if (in_vregion(gs, first)) {
  594. I3d[cnum][X] = first[X];
  595. I3d[cnum][Y] = first[Y];
  596. I3d[cnum][Z] = first[Z];
  597. cnum++;
  598. }
  599. /* TODO: big could still be less than first dist */
  600. big = gs->yrange * gs->yrange + gs->xrange * gs->xrange; /*BIG distance */
  601. dv = dh = dd = big;
  602. for (i = 0; i < num; i = cv + ch + cd) {
  603. if (cv < vi) {
  604. dv = dist_squared_2d(Vi[cv], cpoint);
  605. if (dv < EPSILON) {
  606. cv++;
  607. continue;
  608. }
  609. }
  610. else {
  611. dv = big;
  612. }
  613. if (ch < hi) {
  614. dh = dist_squared_2d(Hi[ch], cpoint);
  615. if (dh < EPSILON) {
  616. ch++;
  617. continue;
  618. }
  619. }
  620. else {
  621. dh = big;
  622. }
  623. if (cd < di) {
  624. dd = dist_squared_2d(Di[cd], cpoint);
  625. if (dd < EPSILON) {
  626. cd++;
  627. continue;
  628. }
  629. }
  630. else {
  631. dd = big;
  632. }
  633. found = 0;
  634. if (cd < di) {
  635. if (dd <= dv && dd <= dh) {
  636. found = 1;
  637. cpoint[X] = I3d[cnum][X] = Di[cd][X];
  638. cpoint[Y] = I3d[cnum][Y] = Di[cd][Y];
  639. I3d[cnum][Z] = Di[cd][Z];
  640. cnum++;
  641. if (EQUAL(dd, dv)) {
  642. cv++;
  643. }
  644. if (EQUAL(dd, dh)) {
  645. ch++;
  646. }
  647. cd++;
  648. }
  649. }
  650. if (!found) {
  651. if (cv < vi) {
  652. if (dv <= dh) {
  653. found = 1;
  654. cpoint[X] = I3d[cnum][X] = Vi[cv][X];
  655. cpoint[Y] = I3d[cnum][Y] = Vi[cv][Y];
  656. I3d[cnum][Z] = Vi[cv][Z];
  657. cnum++;
  658. if (EQUAL(dv, dh)) {
  659. ch++;
  660. }
  661. cv++;
  662. }
  663. }
  664. }
  665. if (!found) {
  666. if (ch < hi) {
  667. cpoint[X] = I3d[cnum][X] = Hi[ch][X];
  668. cpoint[Y] = I3d[cnum][Y] = Hi[ch][Y];
  669. I3d[cnum][Z] = Hi[ch][Z];
  670. cnum++;
  671. ch++;
  672. }
  673. }
  674. if (i == cv + ch + cd) {
  675. G_debug(5, "order_intersects(): stuck on %d", cnum);
  676. G_debug(5, "order_intersects(): cv = %d, ch = %d, cd = %d", cv,
  677. ch, cd);
  678. G_debug(5, "order_intersects(): dv = %f, dh = %f, dd = %f", dv,
  679. dh, dd);
  680. break;
  681. }
  682. }
  683. if (EQUAL(last[X], cpoint[X]) && EQUAL(last[Y], cpoint[Y])) {
  684. return (cnum);
  685. }
  686. if (in_vregion(gs, last)) {
  687. /* TODO: check for last point on corner ? */
  688. I3d[cnum][X] = last[X];
  689. I3d[cnum][Y] = last[Y];
  690. I3d[cnum][Z] = last[Z];
  691. ++cnum;
  692. }
  693. return (cnum);
  694. }
  695. /*!
  696. \brief ADD
  697. \todo For consistancy, need to decide how last row & last column are
  698. displayed - would it look funny to always draw last row/col with
  699. finer resolution if necessary, or would it be better to only show
  700. full rows/cols?
  701. Colinear already eliminated
  702. \param gs surface (geosurf)
  703. \param bgn begin point
  704. \param end end point
  705. \param dir direction
  706. \return
  707. */
  708. int get_vert_intersects(geosurf * gs, float *bgn, float *end, float *dir)
  709. {
  710. int fcol, lcol, incr, hits, num, offset, drow1, drow2;
  711. float xl, yb, xr, yt, z1, z2, alpha;
  712. float xres, yres, xi, yi;
  713. int bgncol, endcol, cols, rows;
  714. xres = VXRES(gs);
  715. yres = VYRES(gs);
  716. cols = VCOLS(gs);
  717. rows = VROWS(gs);
  718. bgncol = X2VCOL(gs, bgn[X]);
  719. endcol = X2VCOL(gs, end[X]);
  720. if (bgncol > cols && endcol > cols) {
  721. return 0;
  722. }
  723. if (bgncol == endcol) {
  724. return 0;
  725. }
  726. fcol = dir[X] > 0 ? bgncol + 1 : bgncol;
  727. lcol = dir[X] > 0 ? endcol : endcol + 1;
  728. /* assuming only showing FULL cols */
  729. incr = lcol - fcol > 0 ? 1 : -1;
  730. while (fcol > cols || fcol < 0) {
  731. fcol += incr;
  732. }
  733. while (lcol > cols || lcol < 0) {
  734. lcol -= incr;
  735. }
  736. num = abs(lcol - fcol) + 1;
  737. yb = gs->yrange - (yres * rows) - EPSILON;
  738. yt = gs->yrange + EPSILON;
  739. for (hits = 0; hits < num; hits++) {
  740. xl = xr = VCOL2X(gs, fcol);
  741. if (segs_intersect(bgn[X], bgn[Y], end[X], end[Y], xl, yt, xr, yb,
  742. &xi, &yi)) {
  743. Vi[hits][X] = xi;
  744. Vi[hits][Y] = yi;
  745. /* find data rows */
  746. if (Flat) {
  747. Vi[hits][Z] = gs->att[ATT_TOPO].constant;
  748. }
  749. else {
  750. drow1 = Y2VROW(gs, Vi[hits][Y]) * gs->y_mod;
  751. drow2 = (1 + Y2VROW(gs, Vi[hits][Y])) * gs->y_mod;
  752. if (drow2 >= gs->rows) {
  753. drow2 = gs->rows - 1; /*bottom edge */
  754. }
  755. alpha =
  756. ((gs->yrange - drow1 * gs->yres) - Vi[hits][Y]) / yres;
  757. offset = DRC2OFF(gs, drow1, fcol * gs->x_mod);
  758. GET_MAPATT(Ebuf, offset, z1);
  759. offset = DRC2OFF(gs, drow2, fcol * gs->x_mod);
  760. GET_MAPATT(Ebuf, offset, z2);
  761. Vi[hits][Z] = LERP(alpha, z1, z2);
  762. }
  763. }
  764. /* if they don't intersect, something's wrong! */
  765. /* should only happen on endpoint, so it will be added later */
  766. else {
  767. hits--;
  768. num--;
  769. }
  770. fcol += incr;
  771. }
  772. return (hits);
  773. }
  774. /*!
  775. \brief Get horizontal intersects
  776. \param gs surface (geosurf)
  777. \param bgn begin point
  778. \param end end point
  779. \param dir
  780. \return number of intersects
  781. */
  782. int get_horz_intersects(geosurf * gs, float *bgn, float *end, float *dir)
  783. {
  784. int frow, lrow, incr, hits, num, offset, dcol1, dcol2;
  785. float xl, yb, xr, yt, z1, z2, alpha;
  786. float xres, yres, xi, yi;
  787. int bgnrow, endrow, rows, cols;
  788. xres = VXRES(gs);
  789. yres = VYRES(gs);
  790. cols = VCOLS(gs);
  791. rows = VROWS(gs);
  792. bgnrow = Y2VROW(gs, bgn[Y]);
  793. endrow = Y2VROW(gs, end[Y]);
  794. if (bgnrow == endrow) {
  795. return 0;
  796. }
  797. if (bgnrow > rows && endrow > rows) {
  798. return 0;
  799. }
  800. frow = dir[Y] > 0 ? bgnrow : bgnrow + 1;
  801. lrow = dir[Y] > 0 ? endrow + 1 : endrow;
  802. /* assuming only showing FULL rows */
  803. incr = lrow - frow > 0 ? 1 : -1;
  804. while (frow > rows || frow < 0) {
  805. frow += incr;
  806. }
  807. while (lrow > rows || lrow < 0) {
  808. lrow -= incr;
  809. }
  810. num = abs(lrow - frow) + 1;
  811. xl = 0.0 - EPSILON;
  812. xr = xres * cols + EPSILON;
  813. for (hits = 0; hits < num; hits++) {
  814. yb = yt = VROW2Y(gs, frow);
  815. if (segs_intersect(bgn[X], bgn[Y], end[X], end[Y], xl, yt, xr, yb,
  816. &xi, &yi)) {
  817. Hi[hits][X] = xi;
  818. Hi[hits][Y] = yi;
  819. /* find data cols */
  820. if (Flat) {
  821. Hi[hits][Z] = gs->att[ATT_TOPO].constant;
  822. }
  823. else {
  824. dcol1 = X2VCOL(gs, Hi[hits][X]) * gs->x_mod;
  825. dcol2 = (1 + X2VCOL(gs, Hi[hits][X])) * gs->x_mod;
  826. if (dcol2 >= gs->cols) {
  827. dcol2 = gs->cols - 1; /* right edge */
  828. }
  829. alpha = (Hi[hits][X] - (dcol1 * gs->xres)) / xres;
  830. offset = DRC2OFF(gs, frow * gs->y_mod, dcol1);
  831. GET_MAPATT(Ebuf, offset, z1);
  832. offset = DRC2OFF(gs, frow * gs->y_mod, dcol2);
  833. GET_MAPATT(Ebuf, offset, z2);
  834. Hi[hits][Z] = LERP(alpha, z1, z2);
  835. }
  836. }
  837. /* if they don't intersect, something's wrong! */
  838. /* should only happen on endpoint, so it will be added later */
  839. else {
  840. hits--;
  841. num--;
  842. }
  843. frow += incr;
  844. }
  845. return (hits);
  846. }
  847. /*!
  848. \brief Get diagonal intersects
  849. Colinear already eliminated
  850. \param gs surface (geosurf)
  851. \param bgn begin point
  852. \param end end point
  853. \param dir ? (unused)
  854. \return number of intersects
  855. */
  856. int get_diag_intersects(geosurf * gs, float *bgn, float *end, float *dir)
  857. {
  858. int fdig, ldig, incr, hits, num, offset;
  859. int vrow, vcol, drow1, drow2, dcol1, dcol2;
  860. float xl, yb, xr, yt, z1, z2, alpha;
  861. float xres, yres, xi, yi, dx, dy;
  862. int diags, cols, rows, lower;
  863. Point3 pt;
  864. xres = VXRES(gs);
  865. yres = VYRES(gs);
  866. cols = VCOLS(gs);
  867. rows = VROWS(gs);
  868. diags = rows + cols; /* -1 ? */
  869. /* determine upper/lower triangle for last */
  870. vrow = Y2VROW(gs, end[Y]);
  871. vcol = X2VCOL(gs, end[X]);
  872. pt[X] = VCOL2X(gs, vcol);
  873. pt[Y] = VROW2Y(gs, vrow + 1);
  874. lower = ((end[X] - pt[X]) / xres > (end[Y] - pt[Y]) / yres);
  875. ldig = lower ? vrow + vcol + 1 : vrow + vcol;
  876. /* determine upper/lower triangle for first */
  877. vrow = Y2VROW(gs, bgn[Y]);
  878. vcol = X2VCOL(gs, bgn[X]);
  879. pt[X] = VCOL2X(gs, vcol);
  880. pt[Y] = VROW2Y(gs, vrow + 1);
  881. lower = ((bgn[X] - pt[X]) / xres > (bgn[Y] - pt[Y]) / yres);
  882. fdig = lower ? vrow + vcol + 1 : vrow + vcol;
  883. /* adjust according to direction */
  884. if (ldig > fdig) {
  885. fdig++;
  886. }
  887. if (fdig > ldig) {
  888. ldig++;
  889. }
  890. incr = ldig - fdig > 0 ? 1 : -1;
  891. while (fdig > diags || fdig < 0) {
  892. fdig += incr;
  893. }
  894. while (ldig > diags || ldig < 0) {
  895. ldig -= incr;
  896. }
  897. num = abs(ldig - fdig) + 1;
  898. for (hits = 0; hits < num; hits++) {
  899. yb = gs->yrange - (yres * (fdig < rows ? fdig : rows)) - EPSILON;
  900. xl = VCOL2X(gs, (fdig < rows ? 0 : fdig - rows)) - EPSILON;
  901. yt = gs->yrange - (yres * (fdig < cols ? 0 : fdig - cols)) + EPSILON;
  902. xr = VCOL2X(gs, (fdig < cols ? fdig : cols)) + EPSILON;
  903. if (segs_intersect(bgn[X], bgn[Y], end[X], end[Y], xl, yb, xr, yt,
  904. &xi, &yi)) {
  905. Di[hits][X] = xi;
  906. Di[hits][Y] = yi;
  907. if (ISNODE(xi, xres)) {
  908. /* then it's also a ynode */
  909. num--;
  910. hits--;
  911. continue;
  912. }
  913. /* find data rows */
  914. drow1 = Y2VROW(gs, Di[hits][Y]) * gs->y_mod;
  915. drow2 = (1 + Y2VROW(gs, Di[hits][Y])) * gs->y_mod;
  916. if (drow2 >= gs->rows) {
  917. drow2 = gs->rows - 1; /* bottom edge */
  918. }
  919. /* find data cols */
  920. if (Flat) {
  921. Di[hits][Z] = gs->att[ATT_TOPO].constant;
  922. }
  923. else {
  924. dcol1 = X2VCOL(gs, Di[hits][X]) * gs->x_mod;
  925. dcol2 = (1 + X2VCOL(gs, Di[hits][X])) * gs->x_mod;
  926. if (dcol2 >= gs->cols) {
  927. dcol2 = gs->cols - 1; /* right edge */
  928. }
  929. dx = DCOL2X(gs, dcol2) - Di[hits][X];
  930. dy = DROW2Y(gs, drow1) - Di[hits][Y];
  931. alpha =
  932. sqrt(dx * dx + dy * dy) / sqrt(xres * xres + yres * yres);
  933. offset = DRC2OFF(gs, drow1, dcol2);
  934. GET_MAPATT(Ebuf, offset, z1);
  935. offset = DRC2OFF(gs, drow2, dcol1);
  936. GET_MAPATT(Ebuf, offset, z2);
  937. Di[hits][Z] = LERP(alpha, z1, z2);
  938. }
  939. }
  940. /* if they don't intersect, something's wrong! */
  941. /* should only happen on endpoint, so it will be added later */
  942. else {
  943. hits--;
  944. num--;
  945. }
  946. fdig += incr;
  947. }
  948. return (hits);
  949. }
  950. /*!
  951. \brief Line intersect
  952. Author: Mukesh Prasad
  953. Modified for floating point: Bill Brown
  954. This function computes whether two line segments,
  955. respectively joining the input points (x1,y1) -- (x2,y2)
  956. and the input points (x3,y3) -- (x4,y4) intersect.
  957. If the lines intersect, the output variables x, y are
  958. set to coordinates of the point of intersection.
  959. \param x1,y1,x2,y2 coordinates of endpoints of one segment
  960. \param x3,y3,x4,y4 coordinates of endpoints of other segment
  961. \param[out] x,y coordinates of intersection point
  962. \return 0 no intersection
  963. \return 1 intersect
  964. \return 2 collinear
  965. */
  966. int segs_intersect(float x1, float y1, float x2, float y2, float x3, float y3,
  967. float x4, float y4, float *x, float *y)
  968. {
  969. float a1, a2, b1, b2, c1, c2; /* Coefficients of line eqns. */
  970. float r1, r2, r3, r4; /* 'Sign' values */
  971. float denom, offset, num; /* Intermediate values */
  972. /* Compute a1, b1, c1, where line joining points 1 and 2
  973. * is "a1 x + b1 y + c1 = 0".
  974. */
  975. a1 = y2 - y1;
  976. b1 = x1 - x2;
  977. c1 = x2 * y1 - x1 * y2;
  978. /* Compute r3 and r4.
  979. */
  980. r3 = a1 * x3 + b1 * y3 + c1;
  981. r4 = a1 * x4 + b1 * y4 + c1;
  982. /* Check signs of r3 and r4. If both point 3 and point 4 lie on
  983. * same side of line 1, the line segments do not intersect.
  984. */
  985. if (!EQUAL(r3, 0.0) && !EQUAL(r4, 0.0) && SAME_SIGNS(r3, r4)) {
  986. return (DONT_INTERSECT);
  987. }
  988. /* Compute a2, b2, c2 */
  989. a2 = y4 - y3;
  990. b2 = x3 - x4;
  991. c2 = x4 * y3 - x3 * y4;
  992. /* Compute r1 and r2 */
  993. r1 = a2 * x1 + b2 * y1 + c2;
  994. r2 = a2 * x2 + b2 * y2 + c2;
  995. /* Check signs of r1 and r2. If both point 1 and point 2 lie
  996. * on same side of second line segment, the line segments do
  997. * not intersect.
  998. */
  999. if (!EQUAL(r1, 0.0) && !EQUAL(r2, 0.0) && SAME_SIGNS(r1, r2)) {
  1000. return (DONT_INTERSECT);
  1001. }
  1002. /* Line segments intersect: compute intersection point.
  1003. */
  1004. denom = a1 * b2 - a2 * b1;
  1005. if (denom == 0) {
  1006. return (COLLINEAR);
  1007. }
  1008. offset = denom < 0 ? -denom / 2 : denom / 2;
  1009. /* The denom/2 is to get rounding instead of truncating. It
  1010. * is added or subtracted to the numerator, depending upon the
  1011. * sign of the numerator.
  1012. */
  1013. num = b1 * c2 - b2 * c1;
  1014. *x = num / denom;
  1015. num = a2 * c1 - a1 * c2;
  1016. *y = num / denom;
  1017. return (DO_INTERSECT);
  1018. }
  1019. /*!
  1020. \brief Check if point is on plane
  1021. Plane defined by three points here; user fills in unk[X] & unk[Y]
  1022. \param p1,p2,p3 points defining plane
  1023. \param unk point
  1024. \return 1 point on plane
  1025. \return 0 point not on plane
  1026. */
  1027. int Point_on_plane(Point3 p1, Point3 p2, Point3 p3, Point3 unk)
  1028. {
  1029. float plane[4];
  1030. P3toPlane(p1, p2, p3, plane);
  1031. return (XY_intersect_plane(unk, plane));
  1032. }
  1033. /*!
  1034. \brief Check for intersection (point and plane)
  1035. Ax + By + Cz + D = 0, so z = (Ax + By + D) / -C
  1036. User fills in intersect[X] & intersect[Y]
  1037. \param[out] intersect intersect coordinates
  1038. \param plane plane definition
  1039. \return 0 doesn't intersect
  1040. \return 1 intesects
  1041. */
  1042. int XY_intersect_plane(float *intersect, float *plane)
  1043. {
  1044. float x, y;
  1045. if (!plane[Z]) {
  1046. return (0); /* doesn't intersect */
  1047. }
  1048. x = intersect[X];
  1049. y = intersect[Y];
  1050. intersect[Z] = (plane[X] * x + plane[Y] * y + plane[W]) / -plane[Z];
  1051. return (1);
  1052. }
  1053. /*!
  1054. \brief Define plane
  1055. \param p1,p2,p3 three point on plane
  1056. \param[out] plane plane defintion
  1057. \return 1
  1058. */
  1059. int P3toPlane(Point3 p1, Point3 p2, Point3 p3, float *plane)
  1060. {
  1061. Point3 v1, v2, norm;
  1062. v1[X] = p1[X] - p3[X];
  1063. v1[Y] = p1[Y] - p3[Y];
  1064. v1[Z] = p1[Z] - p3[Z];
  1065. v2[X] = p2[X] - p3[X];
  1066. v2[Y] = p2[Y] - p3[Y];
  1067. v2[Z] = p2[Z] - p3[Z];
  1068. V3Cross(v1, v2, norm);
  1069. plane[X] = norm[X];
  1070. plane[Y] = norm[Y];
  1071. plane[Z] = norm[Z];
  1072. plane[W] = -p3[X] * norm[X] - p3[Y] * norm[Y] - p3[Z] * norm[Z];
  1073. return (1);
  1074. }
  1075. /*!
  1076. \brief Get cross product
  1077. \param a,b,c
  1078. \return cross product c = a cross b
  1079. */
  1080. int V3Cross(Point3 a, Point3 b, Point3 c)
  1081. {
  1082. c[X] = (a[Y] * b[Z]) - (a[Z] * b[Y]);
  1083. c[Y] = (a[Z] * b[X]) - (a[X] * b[Z]);
  1084. c[Z] = (a[X] * b[Y]) - (a[Y] * b[X]);
  1085. return (1);
  1086. }