3scan.h 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. /****************************************************************************
  2. *
  3. * MODULE: r.terraflow
  4. *
  5. * COPYRIGHT (C) 2007 Laura Toma
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. *****************************************************************************/
  18. #ifndef __3SCAN_H
  19. #define __3SCAN_H
  20. #include <iostream>
  21. using namespace std;
  22. #include <grass/iostream/ami.h>
  23. #include "types.h"
  24. /* ********************************************************************** */
  25. template<class T, class BASETYPE, class FUN>
  26. void
  27. scan3line(FUN &funobj,
  28. AMI_STREAM<T> *prev,
  29. AMI_STREAM<T> *crt,
  30. AMI_STREAM<T> *next,
  31. BASETYPE nodata,
  32. dimension_type i) {
  33. dimension_type j=0;
  34. AMI_err ae;
  35. BASETYPE a[3], b[3], c[3];
  36. T *tmp, center[2];
  37. int done;
  38. /* LOG_DEBUG_ID("scan3line: begin");
  39. if(prev) LOG_DEBUG_ID(prev->sprint());
  40. if(crt) LOG_DEBUG_ID(crt->sprint());
  41. if(next) LOG_DEBUG_ID(next->sprint());
  42. */
  43. /* seek 0 */
  44. if (prev) {
  45. ae = prev->seek(0);
  46. assert(ae == AMI_ERROR_NO_ERROR);
  47. }
  48. assert(crt);
  49. ae = crt->seek(0);
  50. assert(ae == AMI_ERROR_NO_ERROR);
  51. if (next) {
  52. ae = next->seek(0);
  53. assert(ae == AMI_ERROR_NO_ERROR);
  54. }
  55. /* read first 2 elements of each line */
  56. /* read prev */
  57. a[0] = b[0] = c[0] = nodata;
  58. if (prev) {
  59. ae = prev->read_item(&tmp);
  60. assert(ae == AMI_ERROR_NO_ERROR);
  61. a[1] = *tmp;
  62. ae = prev->read_item(&tmp);
  63. assert(ae == AMI_ERROR_NO_ERROR);
  64. a[2] = *tmp;
  65. } else {
  66. a[1] = a[2] = nodata;
  67. }
  68. /* read crt */
  69. ae = crt->read_item(&tmp);
  70. assert(ae == AMI_ERROR_NO_ERROR);
  71. center[0] = *tmp;
  72. b[1] = *tmp;
  73. ae = crt->read_item(&tmp);
  74. assert(ae == AMI_ERROR_NO_ERROR);
  75. center[1] = *tmp;
  76. b[2] = *tmp;
  77. /* read next */
  78. if (next) {
  79. ae = next->read_item(&tmp);
  80. assert(ae == AMI_ERROR_NO_ERROR);
  81. c[1] = *tmp;
  82. ae = next->read_item(&tmp);
  83. assert(ae == AMI_ERROR_NO_ERROR);
  84. c[2] = *tmp;
  85. } else {
  86. c[1] = c[2] = nodata;
  87. }
  88. done = 0;
  89. do {
  90. funobj.processWindow(i, j, center[0], a, b, c); /* process current window*/
  91. /* slide one over */
  92. a[0] = a[1]; a[1] = a[2];
  93. b[0] = b[1]; b[1] = b[2];
  94. center[0] = center[1];
  95. c[0] = c[1]; c[1] = c[2];
  96. j++;
  97. /* read next item from crt and check for EOS */
  98. ae = crt->read_item(&tmp);
  99. if (ae == AMI_ERROR_END_OF_STREAM) {
  100. done = 1;
  101. b[2] = nodata;
  102. center[1] = T();
  103. } else {
  104. assert(ae == AMI_ERROR_NO_ERROR);
  105. b[2] = *tmp;
  106. center[1] = *tmp;
  107. }
  108. /* read next item from prev */
  109. if (prev) {
  110. ae = prev->read_item(&tmp);
  111. if (!done) {
  112. assert(ae == AMI_ERROR_NO_ERROR);
  113. a[2]=*tmp;
  114. } else {
  115. a[2] = nodata;
  116. assert(ae == AMI_ERROR_END_OF_STREAM);
  117. }
  118. } else {
  119. a[2] = nodata;
  120. }
  121. /* read next item from next */
  122. if (next) {
  123. ae = next->read_item(&tmp);
  124. if (!done) {
  125. assert(ae == AMI_ERROR_NO_ERROR);
  126. c[2] = *tmp;
  127. } else {
  128. c[2] = nodata;
  129. assert(ae == AMI_ERROR_END_OF_STREAM);
  130. }
  131. } else {
  132. c[2] = nodata;
  133. }
  134. } while (!done);
  135. /* write last window */
  136. funobj.processWindow(i, j, center[0], a, b, c); /* process current window */
  137. /* LOG_DEBUG_ID("scan3line: end"); */
  138. return;
  139. }
  140. /****************************************************************/
  141. /* amis0 = data (T) in
  142. */
  143. template<class T, class BASETYPE, class FUN>
  144. void
  145. scan3(AMI_STREAM<T> &amis0,
  146. const dimension_type nr, const dimension_type nc, BASETYPE nodata,
  147. FUN &funobj) {
  148. AMI_STREAM<T> *l_prev, *l_crt, *l_next;
  149. AMI_err ae;
  150. ae = amis0.seek(0);
  151. assert( ae == AMI_ERROR_NO_ERROR);
  152. /* scan simultaneously 3 lines in the grid and fill in the windows
  153. use a substream for each line to trigger prefetching */
  154. /* initialize first 2 lines */
  155. ae = amis0.new_substream(AMI_READ_STREAM, 0, nc-1, &l_crt);
  156. assert( ae == AMI_ERROR_NO_ERROR);
  157. ae = amis0.new_substream(AMI_READ_STREAM, nc, 2*nc-1, &l_next);
  158. assert( ae == AMI_ERROR_NO_ERROR);
  159. /* LOG_DEBUG_ID("substreams created"); */
  160. /* process lines, 3 at a time */
  161. l_prev = NULL;
  162. for (dimension_type i=0;i<nr;i++) {
  163. /* process current line */
  164. scan3line(funobj, l_prev, l_crt, l_next, nodata, i);
  165. /* advance lines */
  166. if (l_prev) delete l_prev;
  167. l_prev = l_crt;
  168. l_crt = l_next;
  169. if (i < nr-2) {
  170. ae = amis0.new_substream(AMI_READ_STREAM, (i+2)*nc, (i+3)*nc-1,
  171. &l_next);
  172. assert(ae == AMI_ERROR_NO_ERROR);
  173. } else {
  174. l_next = NULL;
  175. }
  176. }
  177. if (l_prev) delete l_prev;
  178. assert(!l_crt);
  179. /* LOG_DEBUG_ID("scan3: end"); */
  180. return;
  181. }
  182. /* ********************************************************************** */
  183. template<class T>
  184. T *
  185. readLine(T *buf, AMI_STREAM<T> &str, const dimension_type len,
  186. const T &nodata) {
  187. AMI_err ae;
  188. buf[0] = nodata;
  189. buf[len+1] = nodata;
  190. for(dimension_type i=0; i<len; i++) {
  191. T *tmp;
  192. ae = str.read_item(&tmp);
  193. assert(ae==AMI_ERROR_NO_ERROR);
  194. buf[i+1] = *tmp;
  195. }
  196. return buf;
  197. }
  198. /* ********************************************************************** */
  199. template<class T>
  200. T *
  201. setNodata(T *buf, const dimension_type len, const T &nodata) {
  202. for(dimension_type j=0; j<len+2; j++) {
  203. buf[j] = nodata;
  204. }
  205. return buf;
  206. }
  207. /* ********************************************************************** */
  208. /* memoryScan
  209. *
  210. * calls fo.processWindow(i,j, a,b,c) once for each element of the
  211. * grid. i,j are the coordinates in the grid. a,b,c together point
  212. * to the grid surrounding the cell. (b[1] corresponds to cell i,j).
  213. * */
  214. template<class T, class FUN>
  215. void
  216. memoryScan(AMI_STREAM<T> &str,
  217. const dimension_type nrows, const dimension_type ncols,
  218. const T nodata,
  219. FUN &fo) {
  220. T *a, *b, *c;
  221. T *buf[3];
  222. str.seek(0);
  223. assert(nrows > 1);
  224. assert(nrows * ncols == str.stream_len());
  225. buf[0] = new T[ncols+2];
  226. buf[1] = new T[ncols+2];
  227. buf[2] = new T[ncols+2];
  228. unsigned int k;
  229. a = setNodata(buf[0], ncols, nodata);
  230. b = readLine(buf[1], str, ncols, nodata);
  231. k = 2;
  232. for(dimension_type i=0; i<nrows-1; i++) {
  233. c = readLine(buf[k], str, ncols, nodata);
  234. for(dimension_type j=0; j<ncols; j++) {
  235. fo.processWindow(i, j, a+j, b+j, c+j);
  236. }
  237. k = (k+1)%3;
  238. a = b;
  239. b = c;
  240. }
  241. c = setNodata(buf[k], ncols, nodata);
  242. for(dimension_type j=0; j<ncols; j++) {
  243. fo.processWindow(nrows-1, j, a+j, b+j, c+j);
  244. }
  245. delete [] buf[2];
  246. delete [] buf[1];
  247. delete [] buf[0];
  248. }
  249. /* ********************************************************************** */
  250. /* this version uses two streams to make the windows
  251. * FUN should provide a function:
  252. * processWindow(dimension_type i, dimension_type j,
  253. * T1* a1, T1* b1, T1* c1,
  254. * T2* a2, T2* b2, T2* c2)
  255. */
  256. template<class T1, class T2, class FUN>
  257. void
  258. memoryScan(AMI_STREAM<T1> &str1, AMI_STREAM<T2> &str2,
  259. const dimension_type nrows, const dimension_type ncols,
  260. const T1 nodata1, const T2 nodata2,
  261. FUN &fo) {
  262. T1 *a1, *b1, *c1;
  263. T1 *buf1[3];
  264. T2 *a2, *b2, *c2;
  265. T2 *buf2[3];
  266. str1.seek(0);
  267. str2.seek(0);
  268. assert(nrows > 1);
  269. assert(nrows * ncols == str1.stream_len());
  270. assert(nrows * ncols == str2.stream_len());
  271. buf1[0] = new T1[ncols+2];
  272. buf1[1] = new T1[ncols+2];
  273. buf1[2] = new T1[ncols+2];
  274. buf2[0] = new T2[ncols+2];
  275. buf2[1] = new T2[ncols+2];
  276. buf2[2] = new T2[ncols+2];
  277. unsigned int k;
  278. a1 = setNodata(buf1[0], ncols, nodata1);
  279. a2 = setNodata(buf2[0], ncols, nodata2);
  280. b1 = readLine(buf1[1], str1, ncols, nodata1);
  281. b2 = readLine(buf2[1], str2, ncols, nodata2);
  282. k = 2;
  283. for(dimension_type i=0; i<nrows-1; i++) {
  284. c1 = readLine(buf1[k], str1, ncols, nodata1);
  285. c2 = readLine(buf2[k], str2, ncols, nodata2);
  286. for(dimension_type j=0; j<ncols; j++) {
  287. fo.processWindow(i, j, a1+j, b1+j, c1+j,
  288. a2+j, b2+j, c2+j);
  289. }
  290. k = (k+1)%3;
  291. a1 = b1;
  292. a2 = b2;
  293. b1 = c1;
  294. b2 = c2;
  295. }
  296. c1 = setNodata(buf1[k], ncols, nodata1);
  297. c2 = setNodata(buf2[k], ncols, nodata2);
  298. for(dimension_type j=0; j<ncols; j++) {
  299. fo.processWindow(nrows-1, j, a1+j, b1+j, c1+j,
  300. a2+j, b2+j, c2+j);
  301. }
  302. delete [] buf1[2];
  303. delete [] buf1[1];
  304. delete [] buf1[0];
  305. delete [] buf2[2];
  306. delete [] buf2[1];
  307. delete [] buf2[0];
  308. }
  309. #endif