enforce_ds.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. /****************************************************************************
  2. *
  3. * MODULE: r.carve
  4. *
  5. * AUTHOR(S): Original author Bill Brown, UIUC GIS Laboratory
  6. * Brad Douglas <rez touchofmadness com>
  7. *
  8. * PURPOSE: Takes vector stream data, converts it to 3D raster and
  9. * subtracts a specified depth
  10. *
  11. * COPYRIGHT: (C) 2006 by the GRASS Development Team
  12. *
  13. * This program is free software under the GNU General Public
  14. * License (>=v2). Read the file COPYING that comes with GRASS
  15. * for details.
  16. *
  17. ****************************************************************************/
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include <math.h>
  21. #include <grass/gis.h>
  22. #include <grass/raster.h>
  23. #include <grass/glocale.h>
  24. #include "enforce.h"
  25. #ifndef MAX
  26. # define MIN(a,b) ((a<b) ? a : b)
  27. # define MAX(a,b) ((a>b) ? a : b)
  28. #endif
  29. /* function prototypes */
  30. static void clear_bitmap(struct BM *bm);
  31. static int process_line(struct Map_info *Map, struct Map_info *outMap,
  32. void *rbuf, const int line, const struct parms *parm);
  33. static void traverse_line_flat(Point2 * pgpts, const int pt, const int npts);
  34. static void traverse_line_noflat(Point2 * pgpts, const double depth,
  35. const int pt, const int npts);
  36. static void set_min_point(void *buf, const int col, const int row,
  37. const double elev, const double depth,
  38. const RASTER_MAP_TYPE rtype);
  39. static double lowest_cell_near_point(void *data, const RASTER_MAP_TYPE rtype,
  40. const double px, const double py,
  41. const double rad);
  42. static void process_line_segment(const int npts, void *rbuf, Point2 * pgxypts,
  43. Point2 * pgpts, struct BM *bm,
  44. struct Map_info *outMap,
  45. const struct parms *parm);
  46. /******************************************************************
  47. * Returns 0 on success, -1 on error, 1 on warning, writing message
  48. * to errbuf for -1 or 1 */
  49. int enforce_downstream(int infd, int outfd,
  50. struct Map_info *Map, struct Map_info *outMap,
  51. struct parms *parm)
  52. {
  53. struct Cell_head wind;
  54. int retval = 0;
  55. int line, nlines;
  56. void *rbuf = NULL;
  57. /* width used here is actually distance to center of stream */
  58. parm->swidth /= 2;
  59. G_get_window(&wind);
  60. Vect_set_constraint_region(Map, wind.north, wind.south, wind.east,
  61. wind.west, wind.top, wind.bottom);
  62. /* allocate and clear memory for entire raster */
  63. rbuf =
  64. G_calloc(Rast_window_rows() * Rast_window_cols(),
  65. Rast_cell_size(parm->raster_type));
  66. /* first read whole elevation file into buf */
  67. read_raster(rbuf, infd, parm->raster_type);
  68. G_message(_("Processing lines... "));
  69. nlines = Vect_get_num_lines(Map);
  70. for (line = 1; line <= nlines; line++)
  71. retval = process_line(Map, outMap, rbuf, line, parm);
  72. /* write output raster map */
  73. write_raster(rbuf, outfd, parm->raster_type);
  74. G_free(rbuf);
  75. return retval;
  76. }
  77. static int process_line(struct Map_info *Map, struct Map_info *outMap,
  78. void *rbuf, const int line, const struct parms *parm)
  79. {
  80. int i, retval = 0;
  81. int do_warn = 0;
  82. int npts = 0;
  83. int in_out = 0;
  84. int first_in = -1;
  85. double totdist = 0.;
  86. struct Cell_head wind;
  87. static struct line_pnts *points = NULL;
  88. static struct line_cats *cats = NULL;
  89. static struct BM *bm = NULL;
  90. Point2 *pgpts, *pgxypts;
  91. PointGrp pg;
  92. PointGrp pgxy; /* copy any points in region to this one */
  93. G_get_window(&wind);
  94. if (!points)
  95. points = Vect_new_line_struct();
  96. if (!cats)
  97. cats = Vect_new_cats_struct();
  98. if (!(Vect_read_line(Map, points, cats, line) & GV_LINE))
  99. return 0;
  100. if (!bm)
  101. bm = BM_create(Rast_window_cols(), Rast_window_rows());
  102. clear_bitmap(bm);
  103. pg_init(&pg);
  104. pg_init(&pgxy);
  105. G_percent(line, Vect_get_num_lines(Map), 10);
  106. for (i = 0; i < points->n_points; i++) {
  107. Point2 pt, ptxy;
  108. double elev;
  109. int row = Rast_northing_to_row(points->y[i], &wind);
  110. int col = Rast_easting_to_col(points->x[i], &wind);
  111. /* rough clipping */
  112. if (row < 0 || row > Rast_window_rows() - 1 ||
  113. col < 0 || col > Rast_window_cols() - 1) {
  114. if (first_in != -1)
  115. in_out = 1;
  116. G_debug(1, "outside region - row:%d col:%d", row, col);
  117. continue;
  118. }
  119. if (first_in < 0)
  120. first_in = i;
  121. else if (in_out)
  122. do_warn = 1;
  123. elev = lowest_cell_near_point(rbuf, parm->raster_type, points->x[i],
  124. points->y[i], parm->swidth);
  125. ptxy[0] = points->x[i];
  126. ptxy[1] = points->y[i];
  127. pt[1] = elev;
  128. /* get distance from this point to previous point */
  129. if (i)
  130. totdist += G_distance(points->x[i - 1], points->y[i - 1],
  131. points->x[i], points->y[i]);
  132. pt[0] = totdist;
  133. pg_addpt(&pg, pt);
  134. pg_addpt(&pgxy, ptxy);
  135. npts++;
  136. }
  137. if (do_warn) {
  138. G_warning(_("Vect runs out of region and re-enters - "
  139. "this case is not yet implemented."));
  140. retval = 1;
  141. }
  142. /* now check to see if points go downslope(inorder) or upslope */
  143. if (pg_y_from_x(&pg, 0.0) > pg_y_from_x(&pg, totdist)) {
  144. pgpts = pg_getpoints(&pg);
  145. pgxypts = pg_getpoints(&pgxy);
  146. }
  147. else {
  148. /* pgpts is now high to low */
  149. pgpts = pg_getpoints_reversed(&pg);
  150. for (i = 0; i < npts; i++)
  151. pgpts[i][0] = totdist - pgpts[i][0];
  152. pgxypts = pg_getpoints_reversed(&pgxy);
  153. }
  154. for (i = 0; i < (npts - 1); i++) {
  155. if (parm->noflat)
  156. /* make sure there are no flat segments in line */
  157. traverse_line_noflat(pgpts, parm->sdepth, i, npts);
  158. else
  159. /* ok to have flat segments in line */
  160. traverse_line_flat(pgpts, i, npts);
  161. }
  162. process_line_segment(npts, rbuf, pgxypts, pgpts, bm, outMap, parm);
  163. return retval;
  164. }
  165. static void clear_bitmap(struct BM *bm)
  166. {
  167. int i, j;
  168. for (i = 0; i < Rast_window_rows(); i++)
  169. for (j = 0; j < Rast_window_cols(); j++)
  170. BM_set(bm, i, j, 0);
  171. }
  172. static void traverse_line_flat(Point2 * pgpts, const int pt, const int npts)
  173. {
  174. int j, k;
  175. if (pgpts[pt + 1][1] <= pgpts[pt][1])
  176. return;
  177. for (j = (pt + 2); j < npts; j++)
  178. if (pgpts[j][1] <= pgpts[pt][1])
  179. break;
  180. if (j == npts) {
  181. /* if we got to the end, level it out */
  182. for (j = (pt + 1); j < npts; j++)
  183. pgpts[j][1] = pgpts[pt][1];
  184. }
  185. else {
  186. /* linear interp between point pt and the next < */
  187. for (k = (pt + 1); k < j; k++)
  188. pgpts[k][1] = LINTERP(pgpts[j][1], pgpts[pt][1],
  189. (pgpts[j][0] - pgpts[k][0]) /
  190. (pgpts[j][0] - pgpts[pt][0]));
  191. }
  192. }
  193. static void traverse_line_noflat(Point2 * pgpts, const double depth,
  194. const int pt, const int npts)
  195. {
  196. int j, k;
  197. if (pgpts[pt + 1][1] < pgpts[pt][1])
  198. return;
  199. for (j = (pt + 2); j < npts; j++)
  200. if (pgpts[j][1] < pgpts[pt][1])
  201. break;
  202. if (j == npts) {
  203. /* if we got to the end, lower end by depth OR .01 */
  204. --j;
  205. pgpts[j][1] = pgpts[pt][1] - (depth > 0 ? depth : 0.01);
  206. }
  207. /* linear interp between point pt and the next < */
  208. for (k = (pt + 1); k < j; k++)
  209. pgpts[k][1] = LINTERP(pgpts[j][1], pgpts[pt][1],
  210. (pgpts[j][0] - pgpts[k][0]) /
  211. (pgpts[j][0] - pgpts[pt][0]));
  212. }
  213. /* sets value for a cell */
  214. static void set_min_point(void *data, const int col, const int row,
  215. const double elev, const double depth,
  216. const RASTER_MAP_TYPE rtype)
  217. {
  218. switch (rtype) {
  219. case CELL_TYPE:
  220. {
  221. CELL *cbuf = data;
  222. cbuf[row * Rast_window_cols() + col] =
  223. MIN(cbuf[row * Rast_window_cols() + col], elev) - (int)depth;
  224. }
  225. break;
  226. case FCELL_TYPE:
  227. {
  228. FCELL *fbuf = data;
  229. fbuf[row * Rast_window_cols() + col] =
  230. MIN(fbuf[row * Rast_window_cols() + col], elev) - depth;
  231. }
  232. break;
  233. case DCELL_TYPE:
  234. {
  235. DCELL *dbuf = data;
  236. dbuf[row * Rast_window_cols() + col] =
  237. MIN(dbuf[row * Rast_window_cols() + col], elev) - depth;
  238. }
  239. break;
  240. }
  241. }
  242. /* returns the lowest value cell within radius rad of px, py */
  243. static double lowest_cell_near_point(void *data, const RASTER_MAP_TYPE rtype,
  244. const double px, const double py,
  245. const double rad)
  246. {
  247. int r, row, col, row1, row2, col1, col2, rowoff, coloff;
  248. int rastcols, rastrows;
  249. double min;
  250. struct Cell_head wind;
  251. G_get_window(&wind);
  252. rastrows = Rast_window_rows();
  253. rastcols = Rast_window_cols();
  254. Rast_set_d_null_value(&min, 1);
  255. /* kludge - fix for lat_lon */
  256. rowoff = rad / wind.ns_res;
  257. coloff = rad / wind.ew_res;
  258. row = Rast_northing_to_row(py, &wind);
  259. col = Rast_easting_to_col(px, &wind);
  260. /* get bounding box of line segment */
  261. row1 = MAX(0, row - rowoff);
  262. row2 = MIN(rastrows - 1, row + rowoff);
  263. col1 = MAX(0, col - coloff);
  264. col2 = MIN(rastcols - 1, col + coloff);
  265. switch (rtype) {
  266. case CELL_TYPE:
  267. {
  268. CELL *cbuf = data;
  269. if (!(Rast_is_c_null_value(&cbuf[row1 * rastcols + col1])))
  270. min = cbuf[row1 * rastcols + col1];
  271. }
  272. break;
  273. case FCELL_TYPE:
  274. {
  275. FCELL *fbuf = data;
  276. if (!(Rast_is_f_null_value(&fbuf[row1 * rastcols + col1])))
  277. min = fbuf[row1 * rastcols + col1];
  278. }
  279. break;
  280. case DCELL_TYPE:
  281. {
  282. DCELL *dbuf = data;
  283. if (!(Rast_is_d_null_value(&dbuf[row1 * rastcols + col1])))
  284. min = dbuf[row1 * rastcols + col1];
  285. }
  286. break;
  287. }
  288. for (r = row1; r < row2; r++) {
  289. double cy = Rast_row_to_northing(r + 0.5, &wind);
  290. int c;
  291. for (c = col1; c < col2; c++) {
  292. double cx = Rast_col_to_easting(c + 0.5, &wind);
  293. if (G_distance(px, py, cx, cy) <= SQR(rad)) {
  294. switch (rtype) {
  295. case CELL_TYPE:
  296. {
  297. CELL *cbuf = data;
  298. if (Rast_is_d_null_value(&min)) {
  299. if (!(Rast_is_c_null_value(&cbuf[r * rastcols + c])))
  300. min = cbuf[r * rastcols + c];
  301. }
  302. else {
  303. if (!(Rast_is_c_null_value(&cbuf[r * rastcols + c])))
  304. if (cbuf[r * rastcols + c] < min)
  305. min = cbuf[r * rastcols + c];
  306. }
  307. }
  308. break;
  309. case FCELL_TYPE:
  310. {
  311. FCELL *fbuf = data;
  312. if (Rast_is_d_null_value(&min)) {
  313. if (!(Rast_is_f_null_value(&fbuf[r * rastcols + c])))
  314. min = fbuf[r * rastcols + c];
  315. }
  316. else {
  317. if (!(Rast_is_f_null_value(&fbuf[r * rastcols + c])))
  318. if (fbuf[r * rastcols + c] < min)
  319. min = fbuf[r * rastcols + c];
  320. }
  321. }
  322. break;
  323. case DCELL_TYPE:
  324. {
  325. DCELL *dbuf = data;
  326. if (Rast_is_d_null_value(&min)) {
  327. if (!(Rast_is_d_null_value(&dbuf[r * rastcols + c])))
  328. min = dbuf[r * rastcols + c];
  329. }
  330. else {
  331. if (!(Rast_is_d_null_value(&dbuf[r * rastcols + c])))
  332. if (dbuf[r * rastcols + c] < min)
  333. min = dbuf[r * rastcols + c];
  334. }
  335. }
  336. break;
  337. }
  338. }
  339. }
  340. }
  341. G_debug(3, "min:%.2lf", min);
  342. return min;
  343. }
  344. /* Now for each segment in the line, use distance from segment
  345. * to find beginning row from northernmost point, beginning
  346. * col from easternmost, ending row & col, then loop through
  347. * bounding box and use distance from segment to emboss
  348. * new elevations */
  349. static void process_line_segment(const int npts, void *rbuf,
  350. Point2 * pgxypts, Point2 * pgpts,
  351. struct BM *bm, struct Map_info *outMap,
  352. const struct parms *parm)
  353. {
  354. int i, row1, row2, col1, col2;
  355. int prevrow, prevcol;
  356. double cellx, celly, cy;
  357. struct Cell_head wind;
  358. struct line_pnts *points = Vect_new_line_struct();
  359. struct line_cats *cats = Vect_new_cats_struct();
  360. int rowoff, coloff;
  361. G_get_window(&wind);
  362. Vect_cat_set(cats, 1, 1);
  363. /* kludge - fix for lat_lon */
  364. rowoff = parm->swidth / wind.ns_res;
  365. coloff = parm->swidth / wind.ew_res;
  366. /* get prevrow and prevcol for iteration 0 of following loop */
  367. prevrow = Rast_northing_to_row(pgxypts[0][1], &wind);
  368. prevcol = Rast_easting_to_col(pgxypts[0][0], &wind);
  369. for (i = 1; i < npts; i++) {
  370. int c, r;
  371. int row = Rast_northing_to_row(pgxypts[i][1], &wind);
  372. int col = Rast_easting_to_col(pgxypts[i][0], &wind);
  373. /* get bounding box of line segment */
  374. row1 = MAX(0, MIN(row, prevrow) - rowoff);
  375. row2 = MIN(Rast_window_rows() - 1, MAX(row, prevrow) + rowoff);
  376. col1 = MAX(0, MIN(col, prevcol) - coloff);
  377. col2 = MIN(Rast_window_cols() - 1, MAX(col, prevcol) + coloff);
  378. for (r = row1; r <= row2; r++) {
  379. cy = Rast_row_to_northing(r + 0.5, &wind);
  380. for (c = col1; c <= col2; c++) {
  381. double distance;
  382. cellx = Rast_col_to_easting(c + 0.5, &wind);
  383. celly = cy; /* gets written over in distance2... */
  384. /* Thought about not going past endpoints (use
  385. * status to check) but then pieces end up missing
  386. * from outside corners - if it goes past ends,
  387. * should probably do some interp or will get flats.
  388. * Here we use a bitmap and only change cells once
  389. * on the way down */
  390. distance = sqrt(dig_distance2_point_to_line(cellx, celly, 0,
  391. pgxypts[i - 1][0],
  392. pgxypts[i - 1][1], 0,
  393. pgxypts[i][0], pgxypts[i][1],
  394. 0, 0, &cellx, &celly, NULL,
  395. NULL, NULL));
  396. if (distance <= parm->swidth && !BM_get(bm, c, r)) {
  397. double dist, elev;
  398. Vect_reset_line(points);
  399. dist = G_distance(pgxypts[i][0], pgxypts[i][1],
  400. cellx, celly);
  401. elev = LINTERP(pgpts[i][1], pgpts[i - 1][1],
  402. (dist / (pgpts[i][0] - pgpts[i - 1][0])));
  403. BM_set(bm, c, r, 1);
  404. /* TODO - may want to use a function for the
  405. * cross section of stream */
  406. set_min_point(rbuf, c, r, elev, parm->sdepth,
  407. parm->raster_type);
  408. /* Add point to output vector map */
  409. if (parm->outvect->answer) {
  410. Vect_append_point(points, cellx, celly,
  411. elev - parm->sdepth);
  412. Vect_write_line(outMap, GV_POINT, points, cats);
  413. }
  414. }
  415. }
  416. }
  417. prevrow = row;
  418. prevcol = col;
  419. }
  420. }