padrange.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818
  1. /****************************************************************************
  2. *
  3. * MODULE: r.li.padrange
  4. * AUTHOR(S): Serena Pallecchi (original contributor)
  5. * student of Computer Science University of Pisa (Italy)
  6. * Commission from Faunalia Pontedera (PI) www.faunalia.it
  7. * Fixes: Markus Neteler <neteler itc.it>
  8. * Rewrite: Markus Metz
  9. * Patch identification: Michael Shapiro - CERL
  10. *
  11. * PURPOSE: calculates calculates standard deviation of patch areas
  12. * COPYRIGHT: (C) 2007-2014 by the GRASS Development Team
  13. *
  14. * This program is free software under the GNU General Public
  15. * License (>=v2). Read the file COPYING that comes with GRASS
  16. * for details.
  17. *
  18. *****************************************************************************/
  19. #include <stdlib.h>
  20. #include <fcntl.h>
  21. #include <math.h>
  22. #include <grass/gis.h>
  23. #include <grass/raster.h>
  24. #include <grass/glocale.h>
  25. #include "../r.li.daemon/daemon.h"
  26. #include "../r.li.daemon/GenericCell.h"
  27. /* template is patchnum */
  28. /* cell count and type of each patch */
  29. struct pst {
  30. long count;
  31. generic_cell type;
  32. };
  33. rli_func patchAreaDistributionRANGE;
  34. int calculate(int fd, struct area_entry *ad, double *result);
  35. int calculateD(int fd, struct area_entry *ad, double *result);
  36. int calculateF(int fd, struct area_entry *ad, double *result);
  37. int main(int argc, char *argv[])
  38. {
  39. struct Option *raster, *conf, *output;
  40. struct GModule *module;
  41. G_gisinit(argv[0]);
  42. module = G_define_module();
  43. module->description =
  44. _("Calculates range of patch area size on a raster map");
  45. G_add_keyword(_("raster"));
  46. G_add_keyword(_("landscape structure analysis"));
  47. G_add_keyword(_("patch index"));
  48. /* define options */
  49. raster = G_define_standard_option(G_OPT_R_INPUT);
  50. conf = G_define_standard_option(G_OPT_F_INPUT);
  51. conf->key = "config";
  52. conf->description = _("Configuration file");
  53. conf->required = YES;
  54. output = G_define_standard_option(G_OPT_R_OUTPUT);
  55. if (G_parser(argc, argv))
  56. exit(EXIT_FAILURE);
  57. return calculateIndex(conf->answer, patchAreaDistributionRANGE, NULL,
  58. raster->answer, output->answer);
  59. }
  60. int patchAreaDistributionRANGE(int fd, char **par, struct area_entry *ad,
  61. double *result)
  62. {
  63. double indice = 0;
  64. int ris = RLI_OK;
  65. switch (ad->data_type) {
  66. case CELL_TYPE:
  67. {
  68. ris = calculate(fd, ad, &indice);
  69. break;
  70. }
  71. case DCELL_TYPE:
  72. {
  73. ris = calculateD(fd, ad, &indice);
  74. break;
  75. }
  76. case FCELL_TYPE:
  77. {
  78. ris = calculateF(fd, ad, &indice);
  79. break;
  80. }
  81. default:
  82. {
  83. G_fatal_error("data type unknown");
  84. return RLI_ERRORE;
  85. }
  86. }
  87. if (ris != RLI_OK) {
  88. *result = -1;
  89. return RLI_ERRORE;
  90. }
  91. *result = indice;
  92. return RLI_OK;
  93. }
  94. int calculate(int fd, struct area_entry *ad, double *result)
  95. {
  96. CELL *buf, *buf_sup, *buf_null;
  97. CELL corrCell, precCell, supCell;
  98. long npatch, area;
  99. long pid, old_pid, new_pid, *pid_corr, *pid_sup, *ltmp;
  100. struct pst *pst;
  101. long nalloc, incr;
  102. int i, j, k;
  103. int connected;
  104. int mask_fd, *mask_buf, *mask_sup, *mask_tmp, masked;
  105. struct Cell_head hd;
  106. Rast_get_window(&hd);
  107. buf_null = Rast_allocate_c_buf();
  108. Rast_set_c_null_value(buf_null, Rast_window_cols());
  109. buf_sup = buf_null;
  110. /* initialize patch ids */
  111. pid_corr = G_malloc(Rast_window_cols() * sizeof(long));
  112. pid_sup = G_malloc(Rast_window_cols() * sizeof(long));
  113. for (j = 0; j < Rast_window_cols(); j++) {
  114. pid_corr[j] = 0;
  115. pid_sup[j] = 0;
  116. }
  117. /* open mask if needed */
  118. mask_fd = -1;
  119. mask_buf = mask_sup = NULL;
  120. masked = FALSE;
  121. if (ad->mask == 1) {
  122. if ((mask_fd = open(ad->mask_name, O_RDONLY, 0755)) < 0)
  123. return RLI_ERRORE;
  124. mask_buf = G_malloc(ad->cl * sizeof(int));
  125. if (mask_buf == NULL) {
  126. G_fatal_error("malloc mask_buf failed");
  127. return RLI_ERRORE;
  128. }
  129. mask_sup = G_malloc(ad->cl * sizeof(int));
  130. if (mask_sup == NULL) {
  131. G_fatal_error("malloc mask_buf failed");
  132. return RLI_ERRORE;
  133. }
  134. for (j = 0; j < ad->cl; j++)
  135. mask_buf[j] = 0;
  136. masked = TRUE;
  137. }
  138. /* calculate number of patches */
  139. npatch = 0;
  140. area = 0;
  141. pid = 0;
  142. /* patch size and type */
  143. incr = 1024;
  144. if (incr > ad->rl)
  145. incr = ad->rl;
  146. if (incr > ad->cl)
  147. incr = ad->cl;
  148. if (incr < 2)
  149. incr = 2;
  150. nalloc = incr;
  151. pst = G_malloc(nalloc * sizeof(struct pst));
  152. for (k = 0; k < nalloc; k++) {
  153. pst[k].count = 0;
  154. }
  155. for (i = 0; i < ad->rl; i++) {
  156. buf = RLI_get_cell_raster_row(fd, i + ad->y, ad);
  157. if (i > 0) {
  158. buf_sup = RLI_get_cell_raster_row(fd, i - 1 + ad->y, ad);
  159. }
  160. if (masked) {
  161. mask_tmp = mask_sup;
  162. mask_sup = mask_buf;
  163. mask_buf = mask_tmp;
  164. if (read(mask_fd, mask_buf, (ad->cl * sizeof(int))) < 0)
  165. return 0;
  166. }
  167. ltmp = pid_sup;
  168. pid_sup = pid_corr;
  169. pid_corr = ltmp;
  170. Rast_set_c_null_value(&precCell, 1);
  171. connected = 0;
  172. for (j = 0; j < ad->cl; j++) {
  173. pid_corr[j + ad->x] = 0;
  174. corrCell = buf[j + ad->x];
  175. if (masked && (mask_buf[j] == 0)) {
  176. Rast_set_c_null_value(&corrCell, 1);
  177. }
  178. if (Rast_is_c_null_value(&corrCell)) {
  179. connected = 0;
  180. precCell = corrCell;
  181. continue;
  182. }
  183. area++;
  184. supCell = buf_sup[j + ad->x];
  185. if (masked && (mask_sup[j] == 0)) {
  186. Rast_set_c_null_value(&supCell, 1);
  187. }
  188. if (!Rast_is_c_null_value(&precCell) && corrCell == precCell) {
  189. pid_corr[j + ad->x] = pid_corr[j - 1 + ad->x];
  190. connected = 1;
  191. pst[pid_corr[j + ad->x]].count++;
  192. }
  193. else {
  194. connected = 0;
  195. }
  196. if (!Rast_is_c_null_value(&supCell) && corrCell == supCell) {
  197. if (pid_corr[j + ad->x] != pid_sup[j + ad->x]) {
  198. /* connect or merge */
  199. /* after r.clump */
  200. if (connected) {
  201. npatch--;
  202. if (npatch == 0) {
  203. G_fatal_error("npatch == 0 at row %d, col %d", i, j);
  204. }
  205. }
  206. old_pid = pid_corr[j + ad->x];
  207. new_pid = pid_sup[j + ad->x];
  208. pid_corr[j + ad->x] = new_pid;
  209. if (old_pid > 0) {
  210. /* merge */
  211. /* update left side of the current row */
  212. for (k = 0; k < j; k++) {
  213. if (pid_corr[k + ad->x] == old_pid)
  214. pid_corr[k + ad->x] = new_pid;
  215. }
  216. /* update right side of the previous row */
  217. for (k = j + 1; k < ad->cl; k++) {
  218. if (pid_sup[k + ad->x] == old_pid)
  219. pid_sup[k + ad->x] = new_pid;
  220. }
  221. pst[new_pid].count += pst[old_pid].count;
  222. pst[old_pid].count = 0;
  223. if (old_pid == pid)
  224. pid--;
  225. }
  226. else {
  227. pst[new_pid].count++;
  228. }
  229. }
  230. connected = 1;
  231. }
  232. if (!connected) {
  233. /* start new patch */
  234. npatch++;
  235. pid++;
  236. pid_corr[j + ad->x] = pid;
  237. if (pid >= nalloc) {
  238. pst = (struct pst *)G_realloc(pst, (pid + incr) * sizeof(struct pst));
  239. for (k = nalloc; k < pid + incr; k++)
  240. pst[k].count = 0;
  241. nalloc = pid + incr;
  242. }
  243. pst[pid].count = 1;
  244. pst[pid].type.t = CELL_TYPE;
  245. pst[pid].type.val.c = corrCell;
  246. }
  247. precCell = corrCell;
  248. }
  249. }
  250. if (npatch > 0) {
  251. double EW_DIST1, EW_DIST2, NS_DIST1, NS_DIST2;
  252. double area_p;
  253. double cell_size_m;
  254. double min, max;
  255. /* calculate distance */
  256. G_begin_distance_calculations();
  257. /* EW Dist at North edge */
  258. EW_DIST1 = G_distance(hd.east, hd.north, hd.west, hd.north);
  259. /* EW Dist at South Edge */
  260. EW_DIST2 = G_distance(hd.east, hd.south, hd.west, hd.south);
  261. /* NS Dist at East edge */
  262. NS_DIST1 = G_distance(hd.east, hd.north, hd.east, hd.south);
  263. /* NS Dist at West edge */
  264. NS_DIST2 = G_distance(hd.west, hd.north, hd.west, hd.south);
  265. cell_size_m = (((EW_DIST1 + EW_DIST2) / 2) / hd.cols) *
  266. (((NS_DIST1 + NS_DIST2) / 2) / hd.rows);
  267. /* get min and max patch size */
  268. min = 1.0 / 0.0; /* inf */
  269. max = -1.0 / 0.0; /* -inf */
  270. for (old_pid = 1; old_pid <= pid; old_pid++) {
  271. if (pst[old_pid].count > 0) {
  272. area_p = cell_size_m * pst[old_pid].count / 10000;
  273. if (min > area_p)
  274. min = area_p;
  275. if (max < area_p)
  276. max = area_p;
  277. }
  278. }
  279. *result = max - min;
  280. }
  281. else
  282. Rast_set_d_null_value(result, 1);
  283. if (masked) {
  284. close(mask_fd);
  285. G_free(mask_buf);
  286. G_free(mask_sup);
  287. }
  288. G_free(buf_null);
  289. G_free(pid_corr);
  290. G_free(pid_sup);
  291. G_free(pst);
  292. return RLI_OK;
  293. }
  294. int calculateD(int fd, struct area_entry *ad, double *result)
  295. {
  296. DCELL *buf, *buf_sup, *buf_null;
  297. DCELL corrCell, precCell, supCell;
  298. long npatch, area;
  299. long pid, old_pid, new_pid, *pid_corr, *pid_sup, *ltmp;
  300. struct pst *pst;
  301. long nalloc, incr;
  302. int i, j, k;
  303. int connected;
  304. int mask_fd, *mask_buf, *mask_sup, *mask_tmp, masked;
  305. struct Cell_head hd;
  306. Rast_get_window(&hd);
  307. buf_null = Rast_allocate_d_buf();
  308. Rast_set_d_null_value(buf_null, Rast_window_cols());
  309. buf_sup = buf_null;
  310. /* initialize patch ids */
  311. pid_corr = G_malloc(Rast_window_cols() * sizeof(long));
  312. pid_sup = G_malloc(Rast_window_cols() * sizeof(long));
  313. for (j = 0; j < Rast_window_cols(); j++) {
  314. pid_corr[j] = 0;
  315. pid_sup[j] = 0;
  316. }
  317. /* open mask if needed */
  318. mask_fd = -1;
  319. mask_buf = mask_sup = NULL;
  320. masked = FALSE;
  321. if (ad->mask == 1) {
  322. if ((mask_fd = open(ad->mask_name, O_RDONLY, 0755)) < 0)
  323. return RLI_ERRORE;
  324. mask_buf = G_malloc(ad->cl * sizeof(int));
  325. if (mask_buf == NULL) {
  326. G_fatal_error("malloc mask_buf failed");
  327. return RLI_ERRORE;
  328. }
  329. mask_sup = G_malloc(ad->cl * sizeof(int));
  330. if (mask_sup == NULL) {
  331. G_fatal_error("malloc mask_buf failed");
  332. return RLI_ERRORE;
  333. }
  334. for (j = 0; j < ad->cl; j++)
  335. mask_buf[j] = 0;
  336. masked = TRUE;
  337. }
  338. /* calculate number of patches */
  339. npatch = 0;
  340. area = 0;
  341. pid = 0;
  342. /* patch size and type */
  343. incr = 1024;
  344. if (incr > ad->rl)
  345. incr = ad->rl;
  346. if (incr > ad->cl)
  347. incr = ad->cl;
  348. if (incr < 2)
  349. incr = 2;
  350. nalloc = incr;
  351. pst = G_malloc(nalloc * sizeof(struct pst));
  352. for (k = 0; k < nalloc; k++) {
  353. pst[k].count = 0;
  354. }
  355. for (i = 0; i < ad->rl; i++) {
  356. buf = RLI_get_dcell_raster_row(fd, i + ad->y, ad);
  357. if (i > 0) {
  358. buf_sup = RLI_get_dcell_raster_row(fd, i - 1 + ad->y, ad);
  359. }
  360. if (masked) {
  361. mask_tmp = mask_sup;
  362. mask_sup = mask_buf;
  363. mask_buf = mask_tmp;
  364. if (read(mask_fd, mask_buf, (ad->cl * sizeof(int))) < 0)
  365. return 0;
  366. }
  367. ltmp = pid_sup;
  368. pid_sup = pid_corr;
  369. pid_corr = ltmp;
  370. Rast_set_d_null_value(&precCell, 1);
  371. connected = 0;
  372. for (j = 0; j < ad->cl; j++) {
  373. pid_corr[j + ad->x] = 0;
  374. corrCell = buf[j + ad->x];
  375. if (masked && (mask_buf[j] == 0)) {
  376. Rast_set_d_null_value(&corrCell, 1);
  377. }
  378. if (Rast_is_d_null_value(&corrCell)) {
  379. connected = 0;
  380. precCell = corrCell;
  381. continue;
  382. }
  383. area++;
  384. supCell = buf_sup[j + ad->x];
  385. if (masked && (mask_sup[j] == 0)) {
  386. Rast_set_d_null_value(&supCell, 1);
  387. }
  388. if (!Rast_is_d_null_value(&precCell) && corrCell == precCell) {
  389. pid_corr[j + ad->x] = pid_corr[j - 1 + ad->x];
  390. connected = 1;
  391. pst[pid_corr[j + ad->x]].count++;
  392. }
  393. else {
  394. connected = 0;
  395. }
  396. if (!Rast_is_d_null_value(&supCell) && corrCell == supCell) {
  397. if (pid_corr[j + ad->x] != pid_sup[j + ad->x]) {
  398. /* connect or merge */
  399. /* after r.clump */
  400. if (connected) {
  401. npatch--;
  402. if (npatch == 0) {
  403. G_fatal_error("npatch == 0 at row %d, col %d", i, j);
  404. }
  405. }
  406. old_pid = pid_corr[j + ad->x];
  407. new_pid = pid_sup[j + ad->x];
  408. pid_corr[j + ad->x] = new_pid;
  409. if (old_pid > 0) {
  410. /* merge */
  411. /* update left side of the current row */
  412. for (k = 0; k < j; k++) {
  413. if (pid_corr[k + ad->x] == old_pid)
  414. pid_corr[k + ad->x] = new_pid;
  415. }
  416. /* update right side of the previous row */
  417. for (k = j + 1; k < ad->cl; k++) {
  418. if (pid_sup[k + ad->x] == old_pid)
  419. pid_sup[k + ad->x] = new_pid;
  420. }
  421. pst[new_pid].count += pst[old_pid].count;
  422. pst[old_pid].count = 0;
  423. if (old_pid == pid)
  424. pid--;
  425. }
  426. else {
  427. pst[new_pid].count++;
  428. }
  429. }
  430. connected = 1;
  431. }
  432. if (!connected) {
  433. /* start new patch */
  434. npatch++;
  435. pid++;
  436. pid_corr[j + ad->x] = pid;
  437. if (pid >= nalloc) {
  438. pst = (struct pst *)G_realloc(pst, (pid + incr) * sizeof(struct pst));
  439. for (k = nalloc; k < pid + incr; k++)
  440. pst[k].count = 0;
  441. nalloc = pid + incr;
  442. }
  443. pst[pid].count = 1;
  444. pst[pid].type.t = CELL_TYPE;
  445. pst[pid].type.val.c = corrCell;
  446. }
  447. precCell = corrCell;
  448. }
  449. }
  450. if (npatch > 0) {
  451. double EW_DIST1, EW_DIST2, NS_DIST1, NS_DIST2;
  452. double area_p;
  453. double cell_size_m;
  454. double min, max;
  455. /* calculate distance */
  456. G_begin_distance_calculations();
  457. /* EW Dist at North edge */
  458. EW_DIST1 = G_distance(hd.east, hd.north, hd.west, hd.north);
  459. /* EW Dist at South Edge */
  460. EW_DIST2 = G_distance(hd.east, hd.south, hd.west, hd.south);
  461. /* NS Dist at East edge */
  462. NS_DIST1 = G_distance(hd.east, hd.north, hd.east, hd.south);
  463. /* NS Dist at West edge */
  464. NS_DIST2 = G_distance(hd.west, hd.north, hd.west, hd.south);
  465. cell_size_m = (((EW_DIST1 + EW_DIST2) / 2) / hd.cols) *
  466. (((NS_DIST1 + NS_DIST2) / 2) / hd.rows);
  467. /* get min and max patch size */
  468. min = 1.0 / 0.0; /* inf */
  469. max = -1.0 / 0.0; /* -inf */
  470. for (old_pid = 1; old_pid <= pid; old_pid++) {
  471. if (pst[old_pid].count > 0) {
  472. area_p = cell_size_m * pst[old_pid].count / 10000;
  473. if (min > area_p)
  474. min = area_p;
  475. if (max < area_p)
  476. max = area_p;
  477. }
  478. }
  479. *result = max - min;
  480. }
  481. else
  482. Rast_set_d_null_value(result, 1);
  483. if (masked) {
  484. close(mask_fd);
  485. G_free(mask_buf);
  486. G_free(mask_sup);
  487. }
  488. G_free(buf_null);
  489. G_free(pid_corr);
  490. G_free(pid_sup);
  491. G_free(pst);
  492. return RLI_OK;
  493. }
  494. int calculateF(int fd, struct area_entry *ad, double *result)
  495. {
  496. FCELL *buf, *buf_sup, *buf_null;
  497. FCELL corrCell, precCell, supCell;
  498. long npatch, area;
  499. long pid, old_pid, new_pid, *pid_corr, *pid_sup, *ltmp;
  500. struct pst *pst;
  501. long nalloc, incr;
  502. int i, j, k;
  503. int connected;
  504. int mask_fd, *mask_buf, *mask_sup, *mask_tmp, masked;
  505. struct Cell_head hd;
  506. Rast_get_window(&hd);
  507. buf_null = Rast_allocate_f_buf();
  508. Rast_set_f_null_value(buf_null, Rast_window_cols());
  509. buf_sup = buf_null;
  510. /* initialize patch ids */
  511. pid_corr = G_malloc(Rast_window_cols() * sizeof(long));
  512. pid_sup = G_malloc(Rast_window_cols() * sizeof(long));
  513. for (j = 0; j < Rast_window_cols(); j++) {
  514. pid_corr[j] = 0;
  515. pid_sup[j] = 0;
  516. }
  517. /* open mask if needed */
  518. mask_fd = -1;
  519. mask_buf = mask_sup = NULL;
  520. masked = FALSE;
  521. if (ad->mask == 1) {
  522. if ((mask_fd = open(ad->mask_name, O_RDONLY, 0755)) < 0)
  523. return RLI_ERRORE;
  524. mask_buf = G_malloc(ad->cl * sizeof(int));
  525. if (mask_buf == NULL) {
  526. G_fatal_error("malloc mask_buf failed");
  527. return RLI_ERRORE;
  528. }
  529. mask_sup = G_malloc(ad->cl * sizeof(int));
  530. if (mask_sup == NULL) {
  531. G_fatal_error("malloc mask_buf failed");
  532. return RLI_ERRORE;
  533. }
  534. for (j = 0; j < ad->cl; j++)
  535. mask_buf[j] = 0;
  536. masked = TRUE;
  537. }
  538. /* calculate number of patches */
  539. npatch = 0;
  540. area = 0;
  541. pid = 0;
  542. /* patch size and type */
  543. incr = 1024;
  544. if (incr > ad->rl)
  545. incr = ad->rl;
  546. if (incr > ad->cl)
  547. incr = ad->cl;
  548. if (incr < 2)
  549. incr = 2;
  550. nalloc = incr;
  551. pst = G_malloc(nalloc * sizeof(struct pst));
  552. for (k = 0; k < nalloc; k++) {
  553. pst[k].count = 0;
  554. }
  555. for (i = 0; i < ad->rl; i++) {
  556. buf = RLI_get_fcell_raster_row(fd, i + ad->y, ad);
  557. if (i > 0) {
  558. buf_sup = RLI_get_fcell_raster_row(fd, i - 1 + ad->y, ad);
  559. }
  560. if (masked) {
  561. mask_tmp = mask_sup;
  562. mask_sup = mask_buf;
  563. mask_buf = mask_tmp;
  564. if (read(mask_fd, mask_buf, (ad->cl * sizeof(int))) < 0)
  565. return 0;
  566. }
  567. ltmp = pid_sup;
  568. pid_sup = pid_corr;
  569. pid_corr = ltmp;
  570. Rast_set_f_null_value(&precCell, 1);
  571. connected = 0;
  572. for (j = 0; j < ad->cl; j++) {
  573. pid_corr[j + ad->x] = 0;
  574. corrCell = buf[j + ad->x];
  575. if (masked && (mask_buf[j] == 0)) {
  576. Rast_set_f_null_value(&corrCell, 1);
  577. }
  578. if (Rast_is_f_null_value(&corrCell)) {
  579. connected = 0;
  580. precCell = corrCell;
  581. continue;
  582. }
  583. area++;
  584. supCell = buf_sup[j + ad->x];
  585. if (masked && (mask_sup[j] == 0)) {
  586. Rast_set_f_null_value(&supCell, 1);
  587. }
  588. if (!Rast_is_f_null_value(&precCell) && corrCell == precCell) {
  589. pid_corr[j + ad->x] = pid_corr[j - 1 + ad->x];
  590. connected = 1;
  591. pst[pid_corr[j + ad->x]].count++;
  592. }
  593. else {
  594. connected = 0;
  595. }
  596. if (!Rast_is_f_null_value(&supCell) && corrCell == supCell) {
  597. if (pid_corr[j + ad->x] != pid_sup[j + ad->x]) {
  598. /* connect or merge */
  599. /* after r.clump */
  600. if (connected) {
  601. npatch--;
  602. if (npatch == 0) {
  603. G_fatal_error("npatch == 0 at row %d, col %d", i, j);
  604. }
  605. }
  606. old_pid = pid_corr[j + ad->x];
  607. new_pid = pid_sup[j + ad->x];
  608. pid_corr[j + ad->x] = new_pid;
  609. if (old_pid > 0) {
  610. /* merge */
  611. /* update left side of the current row */
  612. for (k = 0; k < j; k++) {
  613. if (pid_corr[k + ad->x] == old_pid)
  614. pid_corr[k + ad->x] = new_pid;
  615. }
  616. /* update right side of the previous row */
  617. for (k = j + 1; k < ad->cl; k++) {
  618. if (pid_sup[k + ad->x] == old_pid)
  619. pid_sup[k + ad->x] = new_pid;
  620. }
  621. pst[new_pid].count += pst[old_pid].count;
  622. pst[old_pid].count = 0;
  623. if (old_pid == pid)
  624. pid--;
  625. }
  626. else {
  627. pst[new_pid].count++;
  628. }
  629. }
  630. connected = 1;
  631. }
  632. if (!connected) {
  633. /* start new patch */
  634. npatch++;
  635. pid++;
  636. pid_corr[j + ad->x] = pid;
  637. if (pid >= nalloc) {
  638. pst = (struct pst *)G_realloc(pst, (pid + incr) * sizeof(struct pst));
  639. for (k = nalloc; k < pid + incr; k++)
  640. pst[k].count = 0;
  641. nalloc = pid + incr;
  642. }
  643. pst[pid].count = 1;
  644. pst[pid].type.t = CELL_TYPE;
  645. pst[pid].type.val.c = corrCell;
  646. }
  647. precCell = corrCell;
  648. }
  649. }
  650. if (npatch > 0) {
  651. double EW_DIST1, EW_DIST2, NS_DIST1, NS_DIST2;
  652. double area_p;
  653. double cell_size_m;
  654. double min, max;
  655. /* calculate distance */
  656. G_begin_distance_calculations();
  657. /* EW Dist at North edge */
  658. EW_DIST1 = G_distance(hd.east, hd.north, hd.west, hd.north);
  659. /* EW Dist at South Edge */
  660. EW_DIST2 = G_distance(hd.east, hd.south, hd.west, hd.south);
  661. /* NS Dist at East edge */
  662. NS_DIST1 = G_distance(hd.east, hd.north, hd.east, hd.south);
  663. /* NS Dist at West edge */
  664. NS_DIST2 = G_distance(hd.west, hd.north, hd.west, hd.south);
  665. cell_size_m = (((EW_DIST1 + EW_DIST2) / 2) / hd.cols) *
  666. (((NS_DIST1 + NS_DIST2) / 2) / hd.rows);
  667. /* get min and max patch size */
  668. min = 1.0 / 0.0; /* inf */
  669. max = -1.0 / 0.0; /* -inf */
  670. for (old_pid = 1; old_pid <= pid; old_pid++) {
  671. if (pst[old_pid].count > 0) {
  672. area_p = cell_size_m * pst[old_pid].count / 10000;
  673. if (min > area_p)
  674. min = area_p;
  675. if (max < area_p)
  676. max = area_p;
  677. }
  678. }
  679. *result = max - min;
  680. }
  681. else
  682. Rast_set_d_null_value(result, 1);
  683. if (masked) {
  684. close(mask_fd);
  685. G_free(mask_buf);
  686. G_free(mask_sup);
  687. }
  688. G_free(buf_null);
  689. G_free(pid_corr);
  690. G_free(pid_sup);
  691. G_free(pst);
  692. return RLI_OK;
  693. }