trace.c 52 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829
  1. /*
  2. ************************************************************
  3. * MODULE: r.le.patch/trace.c *
  4. * Version 5.0 Nov. 1, 2001 *
  5. * *
  6. * AUTHOR: W.L. Baker, University of Wyoming *
  7. * BAKERWL@UWYO.EDU *
  8. * *
  9. * PURPOSE: To analyze attributes of patches in a landscape *
  10. * trace.c traces the patch boundary, obtains basic *
  11. * patch attribute data, and saves this in the *
  12. * patch structure *
  13. * *
  14. * COPYRIGHT: (C) 2001 by W.L. Baker *
  15. * *
  16. * This program is free software under the GNU General *
  17. * Public License(>=v2). Read the file COPYING that comes *
  18. * with GRASS for details *
  19. * *
  20. ************************************************************/
  21. #include <grass/gis.h>
  22. #include <grass/config.h>
  23. #include "patch.h"
  24. extern struct CHOICE *choice;
  25. extern struct REGLIST *reglist;
  26. extern int finput;
  27. int total_patches = 0;
  28. PATCH *patch_list = NULL;
  29. /* DRIVER FOR CELL CLIPPING, TRACING,
  30. AND CALCULATIONS */
  31. void cell_clip_drv(int col0, int row0, int ncols, int nrows, double **value,
  32. int index, float radius)
  33. {
  34. CELL **pat, *pat_buf, *cor_cell_buf;
  35. FCELL *cor_fcell_buf;
  36. DCELL **buf, **cor, *cor_dcell_buf;
  37. DCELL **null_buf;
  38. int i, j, fd, fe, p, infd, centernull = 0, empty = 1;
  39. int hist_ok, colr_ok, cats_ok, range_ok;
  40. char *mapset, *name;
  41. PATCH *list_head;
  42. struct History hist;
  43. struct Categories cats;
  44. struct Categories newcats;
  45. struct Cell_stats stats;
  46. struct Colors colr;
  47. struct Range range;
  48. struct FPRange fprange;
  49. struct Quant quant;
  50. RASTER_MAP_TYPE data_type;
  51. /*
  52. Variables:
  53. EXTERN:
  54. finput = the input raster map
  55. patch_list = the patch list
  56. IN:
  57. col0 = starting column for area to be clipped
  58. row0 = starting row for area to be clipped
  59. ncols = number of columns in area to be clipped
  60. nrows = number of rows in area to be clipped
  61. value = array containing a full row of the results of the moving
  62. window for all the chosen measures if a moving window map,
  63. otherwise 0
  64. index = number of the region to be clipped, if there's a region map,
  65. number of the column if a moving window
  66. INTERNAL:
  67. pat = pointer to array containing the map of patch numbers; this map
  68. can only be integer
  69. pat_buf = row buffer to temporarily hold results for patch number map
  70. buf = pointer to array containing the clipped area, a smaller area
  71. than the original raster map to be read from finput; this map
  72. can be integer, floating point, or double, but is stored as a
  73. double throughout the program
  74. cor = pointer to array containing the map of interior area; this map
  75. can be integer, floating point, or double, but is stored as a
  76. double throughout the program
  77. cor_cell_buf = pointer to row buffer to temporarily hold results for core map if
  78. input map is integer (CELL_TYPE)
  79. cor_fcell_buf = pointer to row buffer to temporarily hold results for core map if
  80. input map is float (FCELL_TYPE)
  81. cor_dcell_buf = pointer to row buffer to temporarily hold results for core map if
  82. input map is double (DCELL_TYPE)
  83. null_buf = pointer to array containing 0.0 if pixel in input raster map is
  84. not null and 1.0 if pixel in input raster map is null
  85. infd = pointer to file with map of patches
  86. i, j = counts the row and column when going through arrays
  87. p = counts the number of measures in
  88. fd = pointer to file to hold patch number map
  89. fe = pointer to file to hold patch interior map
  90. mapset = the name of the mapset for the raster map being analyzed
  91. name = the name of the raster map being analyzed
  92. list_head = point to the patch list
  93. */
  94. total_patches = 0;
  95. name = choice->fn;
  96. mapset = G_mapset();
  97. data_type = Rast_map_type(name, mapset);
  98. /* dynamically allocate storage for the
  99. buffer that will hold the contents of
  100. the clipped area */
  101. buf = (DCELL **) G_calloc(nrows + 3, sizeof(DCELL *));
  102. for (i = 0; i < nrows + 3; i++) {
  103. buf[i] = (DCELL *) Rast_allocate_buf(DCELL_TYPE);
  104. }
  105. /* dynamically allocate storage for the
  106. buffer that will hold the null values for
  107. the clipped area */
  108. null_buf = (DCELL **) G_calloc(nrows + 3, sizeof(DCELL *));
  109. for (i = 0; i < nrows + 3; i++)
  110. null_buf[i] = (DCELL *) Rast_allocate_buf(DCELL_TYPE);
  111. /* if a map of patch cores was requested,
  112. dynamically allocate storage for the
  113. buffer that will temporarily hold the map,
  114. then initialize the buffer with null values */
  115. if (choice->coremap) {
  116. cor = (DCELL **) G_calloc(nrows + 3, sizeof(DCELL *));
  117. for (i = 0; i < nrows + 3; i++) {
  118. cor[i] = (DCELL *) Rast_allocate_buf(DCELL_TYPE);
  119. }
  120. for (i = 0; i < nrows + 3; i++) {
  121. Rast_set_null_value(cor[i], ncols + 3, DCELL_TYPE);
  122. }
  123. }
  124. /* if a map of patch numbers was requested,
  125. dynamically allocate storage for the
  126. buffer that will temporarily hold the map */
  127. if (choice->patchmap) {
  128. pat = (CELL **) G_calloc(nrows + 3, sizeof(CELL *));
  129. for (i = 0; i < nrows + 3; i++)
  130. pat[i] = (CELL *) Rast_allocate_buf(CELL_TYPE);
  131. }
  132. /* clip out the sampling area */
  133. cell_clip(buf, null_buf, row0, col0, nrows, ncols, index, radius,
  134. &centernull, &empty);
  135. /* if the clipped area is not all null values
  136. trace the patches in the sampling area; if
  137. a moving window is used, then the center
  138. pixel must also not be null */
  139. if (!empty) {
  140. if (choice->wrum != 'm') {
  141. trace(nrows, ncols, buf, null_buf, pat, cor);
  142. }
  143. else {
  144. if (!centernull)
  145. trace(nrows, ncols, buf, null_buf, pat, cor);
  146. }
  147. }
  148. /* if a map of patch cores was requested */
  149. if (choice->coremap) {
  150. /* 1. open the source map, then read the
  151. supporting files (cell header, colors,
  152. categories, history, quant) into the
  153. corresponding data structures */
  154. infd = Rast_open_old(name, mapset);
  155. colr_ok = Rast_read_colors(name, mapset, &colr) > 0;
  156. cats_ok = Rast_read_cats(name, mapset, &cats) >= 0;
  157. hist_ok = Rast_read_history(name, mapset, &hist) >= 0;
  158. range_ok = Rast_read_range(name, mapset, &range) >= 0;
  159. /* 2. if map is floating point, then read
  160. the rules for quantization into the quant
  161. data structure; if rules do not exist, create
  162. them by rounding floating point values */
  163. if (data_type != CELL_TYPE) {
  164. Rast_quant_init(&quant);
  165. if (Rast_read_quant(name, mapset, &quant) <= 0)
  166. Rast_quant_round(&quant);
  167. }
  168. /* 3. initialize appropriate data structures */
  169. if (cats_ok)
  170. Rast_init_cats(Rast_get_cats_title(&cats), &newcats);
  171. if (data_type == CELL_TYPE)
  172. Rast_init_cell_stats(&stats);
  173. /* 4. open an output map called "interior" and
  174. copy the contents of the core buffer into
  175. this output map */
  176. switch (data_type) {
  177. case CELL_TYPE:
  178. cor_cell_buf = Rast_allocate_buf(CELL_TYPE);
  179. fe = Rast_open_new("interior", CELL_TYPE);
  180. for (i = 1; i < nrows + 1; i++) {
  181. Rast_zero_buf(cor_cell_buf, CELL_TYPE);
  182. for (j = 1; j < ncols + 1; j++)
  183. *(cor_cell_buf + j - 1) = (int)(*(*(cor + i) + j));
  184. if (Rast_put_row(fe, cor_cell_buf, CELL_TYPE) < 0)
  185. exit(EXIT_FAILURE);
  186. Rast_update_cell_stats(cor_cell_buf, ncols + 1, &stats);
  187. }
  188. break;
  189. case FCELL_TYPE:
  190. cor_fcell_buf = Rast_allocate_buf(FCELL_TYPE);
  191. fe = Rast_open_new("interior", FCELL_TYPE);
  192. for (i = 1; i < nrows + 1; i++) {
  193. Rast_zero_buf(cor_fcell_buf, FCELL_TYPE);
  194. for (j = 1; j < ncols + 1; j++) {
  195. *(cor_fcell_buf + j - 1) = (float)(*(*(cor + i) + j));
  196. }
  197. if (Rast_put_row(fe, cor_fcell_buf, FCELL_TYPE) < 0)
  198. exit(EXIT_FAILURE);
  199. }
  200. break;
  201. case DCELL_TYPE:
  202. cor_dcell_buf = Rast_allocate_buf(DCELL_TYPE);
  203. fe = Rast_open_new("interior", DCELL_TYPE);
  204. for (i = 1; i < nrows + 1; i++) {
  205. Rast_zero_buf(cor_dcell_buf, DCELL_TYPE);
  206. for (j = 1; j < ncols + 1; j++)
  207. *(cor_dcell_buf + j - 1) = (double)(*(*(cor + i) + j));
  208. if (Rast_put_row(fe, cor_dcell_buf, DCELL_TYPE) < 0)
  209. exit(EXIT_FAILURE);
  210. }
  211. break;
  212. }
  213. }
  214. /* if a map of patch numbers was requested,
  215. complete the details of map creation */
  216. if (choice->patchmap) {
  217. fd = Rast_open_new("num", CELL_TYPE);
  218. for (i = 1; i < nrows + 1; i++) {
  219. pat_buf = Rast_allocate_buf(CELL_TYPE);
  220. Rast_zero_buf(pat_buf, CELL_TYPE);
  221. for (j = 1; j < ncols + 1; j++)
  222. *(pat_buf + j - 1) = *(*(pat + i) + j);
  223. if (Rast_put_row(fd, pat_buf, CELL_TYPE) < 0)
  224. exit(EXIT_FAILURE);
  225. }
  226. }
  227. /* print out the patch list */
  228. /* printf("\nPatch list after tracing\n");
  229. list_head = patch_list;
  230. while(list_head) {
  231. printf("num=%d att=%f pts=%d long=%3.0f crow=%3.0f ccol=%3.0f n=%d s=%d
  232. e=%d w=%d area=%3.0f per=%3.0f core=%3.0f edge=%3.0f\n",list_head->num,
  233. list_head->att,
  234. list_head->npts, list_head->long_axis, list_head->c_row,
  235. list_head->c_col, list_head->n,list_head->s,list_head->e,list_head->w,
  236. list_head->area, list_head->perim, list_head->core, list_head->edge);
  237. for (i=0; i<list_head->npts; i++) {
  238. printf("point[%d] row=%d col=%d\n",i,*(list_head->row +
  239. i),*(list_head->col + i));
  240. }
  241. list_head = list_head->next;
  242. }
  243. */
  244. /* if moving window method selected, then
  245. call the moving window driver program */
  246. if (choice->wrum == 'm') {
  247. if (!empty) {
  248. if (!centernull)
  249. mv_patch(patch_list, value, index);
  250. else {
  251. for (p = 0; p < 42; p++)
  252. *(*(value + index) + p) = -BIG;
  253. }
  254. }
  255. else {
  256. for (p = 0; p < 42; p++)
  257. *(*(value + index) + p) = -BIG;
  258. }
  259. }
  260. /* otherwise call the other driver program */
  261. else {
  262. if (!empty)
  263. df_patch(patch_list);
  264. }
  265. /* free memory allocated for content buffer */
  266. for (i = 0; i < nrows + 3; i++)
  267. G_free(buf[i]);
  268. G_free(buf);
  269. /* free memory allocated for null buffer */
  270. for (i = 0; i < nrows + 3; i++)
  271. G_free(null_buf[i]);
  272. G_free(null_buf);
  273. /* free memory allocated for num map */
  274. if (choice->patchmap) {
  275. for (i = 0; i < nrows + 3; i++)
  276. G_free(pat[i]);
  277. G_free(pat);
  278. }
  279. /* free memory allocated for core map */
  280. if (choice->coremap) {
  281. for (i = 0; i < nrows + 3; i++)
  282. G_free(cor[i]);
  283. G_free(cor);
  284. }
  285. /* free memory allocated for patch list */
  286. if (total_patches) {
  287. list_head = patch_list;
  288. while (list_head) {
  289. G_free(list_head->col);
  290. G_free(list_head->row);
  291. G_free(list_head);
  292. list_head = list_head->next;
  293. }
  294. }
  295. /* close the num file and release the
  296. memory allocated for it */
  297. if (choice->patchmap) {
  298. Rast_close(fd);
  299. G_free(pat_buf);
  300. }
  301. /* close the core file, copy the category
  302. information, the statistics, the color
  303. table, and the history over to map
  304. "interior" and then release the
  305. memory allocated for the cor_buf */
  306. if (choice->coremap) {
  307. Rast_close(fe);
  308. Rast_rewind_cell_stats(&stats);
  309. Rast_rewind_cats(&cats);
  310. if (cats_ok && data_type == CELL_TYPE) {
  311. long count;
  312. void *rast1, *rast2;
  313. rast1 = cor_cell_buf;
  314. rast2 = G_incr_void_ptr(rast1, Rast_cell_size(CELL_TYPE));
  315. while (Rast_next_cell_stat(rast1, &count, &stats))
  316. Rast_set_cat(rast1, rast2, Rast_get_cat(rast1, &cats,
  317. CELL_TYPE),
  318. &newcats, CELL_TYPE);
  319. Rast_write_cats("interior", &newcats);
  320. Rast_free_cats(&cats);
  321. Rast_free_cats(&newcats);
  322. Rast_free_cell_stats(&stats);
  323. }
  324. if (colr_ok) {
  325. if (data_type == CELL_TYPE) {
  326. CELL min, max, cmin, cmax;
  327. Rast_read_range("interior", mapset, &range);
  328. Rast_get_range_min_max(&range, &min, &max);
  329. Rast_get_c_color_range(&cmin, &cmax, &colr);
  330. if (min > cmin)
  331. cmin = min;
  332. if (max < cmax)
  333. cmax = max;
  334. Rast_set_c_color_range(cmin, cmax, &colr);
  335. }
  336. else {
  337. DCELL dmin, dmax;
  338. CELL cmin, cmax;
  339. Rast_read_fp_range("interior", mapset, &fprange);
  340. Rast_get_fp_range_min_max(&fprange, &dmin, &dmax);
  341. Rast_get_c_color_range(&cmin, &cmax, &colr);
  342. if (dmin > cmin)
  343. cmin = dmin;
  344. if (dmax < cmax)
  345. cmax = dmax;
  346. Rast_set_c_color_range(cmin, cmax, &colr);
  347. }
  348. Rast_write_colors("interior", mapset, &colr);
  349. }
  350. if (range_ok) {
  351. if (data_type == CELL_TYPE)
  352. Rast_write_range("interior", &range);
  353. else
  354. Rast_write_fp_range("interior", &fprange);
  355. }
  356. if (hist_ok)
  357. Rast_write_history("interior", &hist);
  358. Rast_free_cats(&cats);
  359. Rast_free_colors(&colr);
  360. switch (data_type) {
  361. case CELL_TYPE:
  362. G_free(cor_cell_buf);
  363. break;
  364. case FCELL_TYPE:
  365. G_free(cor_fcell_buf);
  366. break;
  367. case DCELL_TYPE:
  368. G_free(cor_dcell_buf);
  369. break;
  370. }
  371. }
  372. return;
  373. }
  374. /* OPEN THE RASTER FILE TO BE CLIPPED,
  375. AND DO THE CLIPPING */
  376. void cell_clip(DCELL ** buf, DCELL ** null_buf, int row0, int col0, int nrows,
  377. int ncols, int index, float radius, int *centernull,
  378. int *empty)
  379. {
  380. CELL *tmp, *tmp1;
  381. FCELL *ftmp;
  382. DCELL *dtmp;
  383. void *rastptr;
  384. char *tmpname;
  385. int fr, x;
  386. register int i, j;
  387. double center_row = 0.0, center_col = 0.0;
  388. double dist;
  389. RASTER_MAP_TYPE data_type;
  390. /*
  391. Variables:
  392. IN:
  393. buf = pointer to array containing only the pixels inside the area
  394. that was specified to be clipped, so a smaller array than the
  395. original raster map
  396. null_buf = pointer to array containing 0.0 if pixel in input raster map is
  397. not null and 1.0 if pixel in input raster map is null
  398. row0 = starting row for the area to be clipped out of the raster map
  399. col0 = starting col for the area to be clipped out of the raster map
  400. nrows = total number of rows in the area to be clipped
  401. ncols = total number of cols in the area to be clipped
  402. index = number of the region to be clipped, if there's a region map
  403. radius = radius of the circle to be clipped, if circles chosen for
  404. sampling units
  405. centernull = 1 if the center pixel of the clipped area is a null value,
  406. 0 otherwise
  407. empty = 1 is the whole clipped area contains null values, 0 otherwise.
  408. INTERNAL:
  409. tmp = pointer to a temporary buffer to store a row of a CELL_TYPE
  410. (integer) raster
  411. ftmp = pointer to a temporary buffer to store a row of an FCELL_TYPE
  412. (floating point) raster
  413. dtmp = pointer to a temporary buffer to store a row of a DCELL_TYPE
  414. (double) raster
  415. tmp1 = pointer to a temporary buffer to store a row of the region map
  416. tmpname = one of the above: tmp, ftmp, dtmp
  417. fr = return value from attempting to open the region map
  418. i, j = indices to rows and cols of the arrays
  419. center_row = row of the center of the circle, if circles used
  420. center_col = column of the center of the circle, if circles used
  421. dist = used to measure distance from a row/column to the center of the
  422. circle, to see if a row/column is within the circle
  423. data_type = the type of raster map: integer, floating point, or double
  424. rastptr = void pointer used to advance through null values in the tmp,
  425. ftmp, or dtmp buffers
  426. */
  427. /* if sampling by region was chosen, check
  428. for the region map and make sure it is
  429. an integer (CELL_TYPE) map */
  430. if (choice->wrum == 'r') {
  431. if (0 > (fr = Rast_open_old(choice->reg, G_mapset()))) {
  432. fprintf(stderr, "\n");
  433. fprintf(stderr,
  434. " *******************************************************\n");
  435. fprintf(stderr,
  436. " You specified sam=r to request sampling by region, \n");
  437. fprintf(stderr,
  438. " but the region map specified with the 'reg=' parameter\n");
  439. fprintf(stderr,
  440. " cannot be found in the current mapset. \n");
  441. fprintf(stderr,
  442. " *******************************************************\n");
  443. exit(EXIT_FAILURE);
  444. }
  445. if (Rast_map_type(choice->reg, G_mapset()) > 0) {
  446. fprintf(stderr, "\n");
  447. fprintf(stderr,
  448. " *******************************************************\n");
  449. fprintf(stderr,
  450. " You specified sam=r to request sampling by region, \n");
  451. fprintf(stderr,
  452. " but the region map specified with the 'reg=' parameter\n");
  453. fprintf(stderr,
  454. " must be an integer map, and it is floating point or \n");
  455. fprintf(stderr,
  456. " double instead. \n");
  457. fprintf(stderr,
  458. " *******************************************************\n");
  459. exit(EXIT_FAILURE);
  460. }
  461. tmp1 = Rast_allocate_buf(CELL_TYPE);
  462. Rast_zero_buf(tmp1, CELL_TYPE);
  463. fprintf(stderr, "Analyzing region number %d...\n", index);
  464. }
  465. data_type = Rast_map_type(choice->fn, G_mapset());
  466. /* allocate memory to store a row of the
  467. raster map, depending on the type of
  468. input raster map; keep track of the
  469. name of the buffer for each raster type */
  470. switch (data_type) {
  471. case CELL_TYPE:
  472. tmp = Rast_allocate_buf(CELL_TYPE);
  473. tmpname = "tmp";
  474. break;
  475. case FCELL_TYPE:
  476. ftmp = Rast_allocate_buf(FCELL_TYPE);
  477. tmpname = "ftmp";
  478. break;
  479. case DCELL_TYPE:
  480. dtmp = Rast_allocate_buf(DCELL_TYPE);
  481. tmpname = "dtmp";
  482. break;
  483. }
  484. /* zero the buffer used to hold null values */
  485. for (i = 0; i < nrows; i++) {
  486. for (j = 0; j < ncols; j++) {
  487. null_buf[i][j] = 1.0;
  488. }
  489. }
  490. /* if circles are used for sampling, then
  491. calculate the center of the area to be
  492. clipped, in pixels */
  493. if ((int)radius) {
  494. center_row = ((double)row0 + ((double)nrows - 1) / 2);
  495. center_col = ((double)col0 + ((double)ncols - 1) / 2);
  496. }
  497. /* for each row of the area to be clipped */
  498. /*printf("\n\nNEW WINDOW\n"); */
  499. for (i = row0; i < row0 + nrows; i++) {
  500. /* if region, read in the corresponding
  501. map row in the region file */
  502. if (choice->wrum == 'r')
  503. Rast_get_row_nomask(fr, tmp1, i, CELL_TYPE);
  504. /* initialize each element of the
  505. row buffer to 0; this row buffer
  506. will hold one row of the clipped
  507. raster map. Then read row i of the
  508. map into tmp buffer */
  509. switch (data_type) {
  510. case CELL_TYPE:
  511. Rast_zero_buf(tmp, data_type);
  512. Rast_get_row(finput, tmp, i, data_type);
  513. break;
  514. case FCELL_TYPE:
  515. Rast_zero_buf(ftmp, data_type);
  516. Rast_get_row(finput, ftmp, i, data_type);
  517. break;
  518. case DCELL_TYPE:
  519. Rast_zero_buf(dtmp, data_type);
  520. Rast_get_row(finput, dtmp, i, data_type);
  521. break;
  522. }
  523. /* set up a void pointer to be used to find null
  524. values in the area to be clipped and advance
  525. the raster pointer to the right starting
  526. column */
  527. switch (data_type) {
  528. case CELL_TYPE:
  529. rastptr = tmp;
  530. for (x = 0; x < col0; x++)
  531. rastptr = G_incr_void_ptr(rastptr, Rast_cell_size(CELL_TYPE));
  532. break;
  533. case FCELL_TYPE:
  534. rastptr = ftmp;
  535. for (x = 0; x < col0; x++)
  536. rastptr = G_incr_void_ptr(rastptr, Rast_cell_size(FCELL_TYPE));
  537. break;
  538. case DCELL_TYPE:
  539. rastptr = dtmp;
  540. for (x = 0; x < col0; x++)
  541. rastptr = G_incr_void_ptr(rastptr, Rast_cell_size(DCELL_TYPE));
  542. break;
  543. }
  544. /* for all the columns one by one */
  545. for (j = col0; j < col0 + ncols; j++) {
  546. /* look for null values in each cell
  547. and set centernull flag to 1 if
  548. center is null and empty to 1 if
  549. no cells are found that are not null */
  550. switch (data_type) {
  551. case CELL_TYPE:
  552. if (Rast_is_null_value(rastptr, CELL_TYPE)) {
  553. *(*(null_buf + i + 1 - row0) + j + 1 - col0) = 1.0;
  554. if (i == row0 + nrows / 2 && j == col0 + ncols / 2)
  555. *centernull = 1;
  556. }
  557. else {
  558. *empty = 0;
  559. if (choice->wrum != 'r' || *(tmp1 + j) == index)
  560. *(*(null_buf + i + 1 - row0) + j + 1 - col0) = 0.0;
  561. else
  562. *(*(null_buf + i + 1 - row0) + j + 1 - col0) = 1.0;
  563. }
  564. rastptr = G_incr_void_ptr(rastptr, Rast_cell_size(CELL_TYPE));
  565. break;
  566. case FCELL_TYPE:
  567. if (Rast_is_null_value(rastptr, FCELL_TYPE)) {
  568. *(*(null_buf + i + 1 - row0) + j + 1 - col0) = 1.0;
  569. if (i == row0 + nrows / 2 && j == col0 + ncols / 2)
  570. *centernull = 1;
  571. }
  572. else {
  573. *empty = 0;
  574. if (choice->wrum != 'r' || *(tmp1 + j) == index)
  575. *(*(null_buf + i + 1 - row0) + j + 1 - col0) = 0.0;
  576. else
  577. *(*(null_buf + i + 1 - row0) + j + 1 - col0) = 1.0;
  578. }
  579. rastptr = G_incr_void_ptr(rastptr, Rast_cell_size(FCELL_TYPE));
  580. break;
  581. case DCELL_TYPE:
  582. if (Rast_is_null_value(rastptr, DCELL_TYPE)) {
  583. *(*(null_buf + i + 1 - row0) + j + 1 - col0) = 1.0;
  584. if (i == row0 + nrows / 2 && j == col0 + ncols / 2)
  585. *centernull = 1;
  586. }
  587. else {
  588. *empty = 0;
  589. if (choice->wrum != 'r' || *(tmp1 + j) == index)
  590. *(*(null_buf + i + 1 - row0) + j + 1 - col0) = 0.0;
  591. else
  592. *(*(null_buf + i + 1 - row0) + j + 1 - col0) = 1.0;
  593. }
  594. rastptr = G_incr_void_ptr(rastptr, Rast_cell_size(CELL_TYPE));
  595. break;
  596. }
  597. /* if circles are used for sampling */
  598. if ((int)radius) {
  599. dist =
  600. sqrt(((double)i - center_row) * ((double)i - center_row) +
  601. ((double)j - center_col) * ((double)j - center_col));
  602. /* copy the contents of the correct tmp file
  603. into the appropriate cell in the buf */
  604. if (dist < radius) {
  605. switch (data_type) {
  606. case CELL_TYPE:
  607. *(*(buf + i + 1 - row0) + j + 1 - col0) = *(tmp + j);
  608. break;
  609. case FCELL_TYPE:
  610. *(*(buf + i + 1 - row0) + j + 1 - col0) = *(ftmp + j);
  611. break;
  612. case DCELL_TYPE:
  613. *(*(buf + i + 1 - row0) + j + 1 - col0) = *(dtmp + j);
  614. break;
  615. }
  616. }
  617. else
  618. *(*(null_buf + i + 1 - row0) + j + 1 - col0) = 1.0;
  619. }
  620. /* if circles are not used and
  621. if the choice is not "by region" or
  622. if this column is in region "index" */
  623. else if (choice->wrum != 'r' || *(tmp1 + j) == index) {
  624. /* copy the contents of the correct tmp
  625. into the appropriate cell in the buf
  626. and the corresponding null values into
  627. the appropriate cell in null_buf */
  628. switch (data_type) {
  629. case CELL_TYPE:
  630. *(*(buf + i + 1 - row0) + j + 1 - col0) = *(tmp + j);
  631. break;
  632. case FCELL_TYPE:
  633. *(*(buf + i + 1 - row0) + j + 1 - col0) = *(ftmp + j);
  634. break;
  635. case DCELL_TYPE:
  636. *(*(buf + i + 1 - row0) + j + 1 - col0) = *(dtmp + j);
  637. break;
  638. }
  639. /*printf("cell_clip i=%d j=%d buf= %12.0f null_buf = %d\n", i, j,
  640. *(*(buf +i+1-row0)+j+1-col0), *(*(null_buf +i +1-row0) +j +1 -col0)); */
  641. }
  642. }
  643. }
  644. switch (data_type) {
  645. case CELL_TYPE:
  646. G_free(tmp);
  647. break;
  648. case FCELL_TYPE:
  649. G_free(ftmp);
  650. break;
  651. case DCELL_TYPE:
  652. G_free(dtmp);
  653. break;
  654. }
  655. if (choice->wrum == 'r') {
  656. G_free(tmp1);
  657. Rast_close(fr);
  658. }
  659. return;
  660. }
  661. /* DRIVER TO LOOK FOR NEW PATCHES, CALL
  662. THE TRACING ROUTINE, AND ADD NEW PATCHES
  663. TO THE PATCH LIST */
  664. void trace(int nrows, int ncols, DCELL ** buf, DCELL ** null_buf, CELL ** pat,
  665. DCELL ** cor)
  666. {
  667. double class = 0.0;
  668. register int i, j;
  669. PATCH *tmp, *find_any, *list_head;
  670. /*
  671. Variables:
  672. EXTERN:
  673. IN:
  674. nrows = total number of rows in the area where tracing will occur
  675. ncols = total number of cols in the area where tracing will occur
  676. buf = pointer to array containing only the pixels inside the area
  677. that was clipped and within which tracing will now occur, so
  678. a smaller array than the original raster map
  679. null_buf = pointer to array containing 0.0 if pixel in input raster map is
  680. not null and 1.0 if pixel in input raster map is null
  681. pat = pointer to array containing the map of patch numbers; this map
  682. can only be integer
  683. cor = pointer to array containing the map of interior area; this map
  684. can be integer, floating point, or double, but is stored as a
  685. double throughout the program
  686. INTERNAL:
  687. class = the attribute of each pixel
  688. i, j = counts the row and column as the program goes through the area
  689. tmp = pointer to a member of the PATCH list data structure, used to
  690. advance through the patch list
  691. find_any = pointer to a member of the patch list to hold the results after
  692. routine get_bd is called to trace the boundary of the patch and
  693. save the patch information in the PATCH data structure
  694. list_head = pointer to the first member of the patch list
  695. */
  696. /* go thru buf, which contains the entries
  697. within the clipped window, column by
  698. column and row by row; Note that now the
  699. rows and cols are counted from 1 to nrows
  700. and 1 to ncols, not from 0 to < nrows and
  701. 0 to < ncols */
  702. i = 0;
  703. while (i++ < nrows) { /*1 */
  704. j = 0;
  705. while (j++ < ncols) {
  706. /* if this pt contains a positive or negative
  707. raster value or a zero, and null value is
  708. 0.0, it may be the start of an untraced
  709. patch */
  710. if ((*(*(buf + i) + j) || *(*(buf + i) + j) == 0.0) && *(*(null_buf + i) + j) == 0.0) { /*3 */
  711. class = *(*(buf + i) + j);
  712. /* trace the patch from the current pt */
  713. list_head = patch_list;
  714. if ((find_any = get_bd(i, j, nrows, ncols, class, buf, null_buf, list_head, pat, cor))) { /*4 */
  715. /* if the first patch, make tmp point to
  716. the patch list and add the first patch
  717. to the list */
  718. if (total_patches == 0) {
  719. patch_list = find_any;
  720. tmp = patch_list;
  721. }
  722. /* add the next patch to the patch list */
  723. else {
  724. tmp->next = find_any;
  725. tmp = tmp->next;
  726. }
  727. /* increment the count of total patches */
  728. total_patches++;
  729. } /*4 */
  730. /* if i and j are now at or outside the
  731. limits of the window, then quit */
  732. if (i >= nrows && j >= ncols) {
  733. return;
  734. }
  735. } /*3 */
  736. /* if this pt is the boundary point of an
  737. already traced patch or is outside the
  738. window, do not start tracing; skip to
  739. next pt */
  740. else { /*5 */
  741. /* if i and j are now at or outside the
  742. limits of the window, then quit */
  743. if (i >= nrows && j >= ncols)
  744. return;
  745. } /*5 */
  746. } /*2 */
  747. }
  748. return; /*1 */
  749. }
  750. /* TRACE THE BOUNDARY OF A PATCH AND
  751. SAVE THE PATCH CHARACTERISTICS IN
  752. THE PATCH STRUCTURE */
  753. PATCH *get_bd(int row0, int col0, int nrows, int ncols, double class,
  754. DCELL ** buf, DCELL ** null_buf, PATCH * p_list, CELL ** pat,
  755. DCELL ** cor)
  756. {
  757. int i = row0, j = col0, pts = 0, di = 0, dj = -1,
  758. not_done, k, m, tmp, lng = 0, roww = 0, rowe = 0,
  759. row1, col1, di2, dj2, p, q, area, per, corearea, edgearea, nozero;
  760. int ***twist2, trows, tcols, n, e, a, b;
  761. float ***twistP, sumT;
  762. PATCH *patch;
  763. CELL **patchmap;
  764. PT *ptrfirst, *ptrthis, *ptrnew, *ptrfree;
  765. /*
  766. Variables:
  767. IN:
  768. row0 = row for the first pixel in the patch
  769. col0 = column for the first pixel in the patch
  770. nrows = number of rows in the clipped area
  771. ncols = number of columns in the clipped area
  772. class = attribute of the patch being traced
  773. buf = pointer to array containing only the pixels inside the area
  774. that was clipped
  775. null_buf = pointer to array containing 0.0 if pixel in input raster map is
  776. not null and 1.0 if pixel in input raster map is null
  777. p_list = pointer to the patch list
  778. pat = pointer to array containing the map of patch numbers; this map
  779. can only be integer
  780. cor = pointer to array containing the map of interior area; this map
  781. can be integer, floating point, or double, but is stored as a
  782. double throughout the program
  783. INTERNAL
  784. i, j = counts the row and column as tracing occurs
  785. pts = counts the number of points as tracing proceeds
  786. di, dj = indicates moves of 1 pixel in the row or column direction, used
  787. to examine adjoining 4- or 8-neighboring pixels when tracing
  788. not_done = flag to indicate when the patch has not been fully traced yet
  789. k =
  790. m =
  791. tmp = integer to hold intermediate results in calculation of long axis
  792. of patch
  793. lng = integer to hold the calculated long axis of the patch
  794. roww = integer to hold the westernmost point in each row of the patch
  795. rowe = integer to hold the easternmost point in each row of the patch
  796. coln = integer to hold the northernmost point in each row of the patch
  797. cols = integer to hold the southernmost point in each row of the patch
  798. row1 = integer to hold the starting row for tracing internal boundaries
  799. col1 = integer to hold the starting column for tracing internal boundaries
  800. di2, dj2 = indicates moves of 1 pixel in the row or column direction, used
  801. to examine adjoining 4- or 8-neighboring pixels when tracing
  802. internal boundaries of a patch
  803. p, q = row and column indices for tracing patch internal boundaries
  804. area = patch area
  805. per = patch perimeter
  806. corearea = patch interior area
  807. edgearea = patch edge area
  808. nozero =
  809. twist2 = 2-dimensional array to hold preliminary countes needed to calculate
  810. the twist number and omega index
  811. trows = number of rows in the bounding box for the patch
  812. tcols = number of columns in the bounding box for the patch
  813. n, e = northing (in rows) and easting (in columns) for the patch
  814. a, b = indexes particular pixels used in calculating twist number in certain
  815. cases
  816. twistnum = twist number
  817. twistP = 2-dimensional array to hold P values used in the calculation of twist
  818. number
  819. sumT = the floating point version of twist number
  820. omega = omega index
  821. patch = pointer to a member of the patch list
  822. patchmap = 2-dimensional array holding 1's for pixels inside the patch and
  823. zero otherwise
  824. ptrfirst = pointer to the first element of the linked list of patches
  825. ptrthis = pointer to the current element of the linked list of patches
  826. ptrnew = pointer to a new element of the linked list of patches
  827. ptrfree =
  828. */
  829. /* allocate memory for 1 patch to be
  830. saved in the patch data structure */
  831. patch = (PATCH *) G_calloc(1, sizeof(PATCH));
  832. /* allocate memory for patchmap, which
  833. will hold the patch boundaries found in
  834. the buf array */
  835. patchmap = (CELL **) G_calloc(nrows + 3, sizeof(CELL *));
  836. for (m = 0; m < nrows + 3; m++)
  837. patchmap[m] = (CELL *) Rast_allocate_buf(CELL_TYPE);
  838. /* print on the screen a message indicating
  839. that tracing has reached a certain patch */
  840. if (choice->wrum != 'm') {
  841. fprintf(stderr, "Tracing patch %7d\r", total_patches + 1);
  842. }
  843. /* if this is the first patch to be traced,
  844. then set the next patch on the patch list
  845. to NULL */
  846. if (total_patches == 0)
  847. patch->next = (PATCH *) NULL;
  848. /* this loop goes until the patch has been
  849. traced */
  850. for (;;) { /*1 */
  851. /* STEP 1: RECORD ATTRIBUTE AND PATCH NUMBER,
  852. THEN TRACE THE PTS IN THE BOUNDARY,
  853. RECORDING THE ROW AND COL OF EACH PT, AND
  854. FINDING THE PATCH BOUNDING BOX */
  855. /* initialize variables */
  856. not_done = 1;
  857. patch->s = 0;
  858. patch->e = 0;
  859. patch->w = (int)BIG;
  860. patch->n = (int)BIG;
  861. /* while tracing is not done */
  862. while (not_done) { /*2 */
  863. /* if this is the first pt in the patch,
  864. fill the PATCH structure with the
  865. attribute and number of the patch,
  866. and set the first pt to NULL */
  867. if (pts == 0) {
  868. patch->att = class;
  869. patch->num = total_patches + 1;
  870. ptrfirst = (PT *) NULL;
  871. }
  872. /* if this pt has a non-null value and
  873. it hasn't been traced.
  874. (1) put a 1 in patchmap at the location.
  875. This will keep track of all the pixels
  876. that get traced in this one patch.
  877. (2) make the null_buf value a 1.0. This
  878. will keep track of all the pixels that
  879. get traced or are otherwise null in all
  880. the patches in the buffer. Once they
  881. are null, they don't get traced again.
  882. (3) save the row & col in PATCH structure,
  883. (4) see if the pt expands the current
  884. bounding box
  885. (5) increment the pts count */
  886. /*printf("num=%d i=%d j=%d buf=%f patchmap=%d null=%f START GET_BD\n",
  887. patch->num,i,j,*(*(buf + i) + j),*(*(patchmap + i) + j), *(*(null_buf + i) +
  888. j)); */
  889. if ((*(*(buf + i) + j) ||
  890. *(*(buf + i) + j) == 0.0) &&
  891. *(*(patchmap + i) + j) == 0 &&
  892. *(*(null_buf + i) + j) == 0.0) {
  893. *(*(patchmap + i) + j) = 1;
  894. *(*(null_buf + i) + j) = 1.0;
  895. ptrnew = (PT *) G_calloc(1, sizeof(PT));
  896. if (ptrfirst == (PT *) NULL) {
  897. ptrfirst = ptrthis = ptrnew;
  898. }
  899. else {
  900. ptrthis = ptrfirst;
  901. while (ptrthis->next != (PT *) NULL)
  902. ptrthis = ptrthis->next;
  903. ptrthis->next = ptrnew;
  904. ptrthis = ptrnew;
  905. }
  906. ptrthis->row = i;
  907. ptrthis->col = j;
  908. if (i > patch->s)
  909. patch->s = i;
  910. if (i < patch->n)
  911. patch->n = i;
  912. if (j > patch->e)
  913. patch->e = j;
  914. if (j < patch->w)
  915. patch->w = j;
  916. pts++;
  917. }
  918. /*printf("3. i=%d j=%d s=%d n=%d w=%d e=%d\n",i,j, patch->s, patch->n,
  919. patch->w,patch->e); */
  920. /* if there is a neighboring pixel, with the
  921. same class, moving clockwise around the
  922. patch, then reset i and j to this
  923. location, then reset di and dj */
  924. if (yes_nb(&di, &dj, buf, class, i, j, nrows, ncols)) {
  925. i = i + di;
  926. j = j + dj;
  927. di = -di;
  928. dj = -dj;
  929. clockwise(&di, &dj);
  930. /*printf("num=%d i=%d j=%d buf=%f patchmap=%d null=%d row0=%d col0=%d \
  931. AFTER YES_NB\n",
  932. patch->num,i,j, *(*(buf + i) + j), *(*(patchmap + i) + j),
  933. *(*(null_buf + i) + j), row0, col0);
  934. */
  935. /* if tracing has returned to the starting
  936. pt, then stop; in a special case with
  937. diagonal tracing, don't stop if there is
  938. a traceable pixel below and to the left
  939. and if there is a below and to the left */
  940. if (i == row0 && j == col0) {
  941. not_done = 0;
  942. if (choice->trace &&
  943. (i < nrows) && (j > 1) &&
  944. *(*(buf + i + 1) + j - 1) == class &&
  945. (*(*(patchmap + i + 1) + j - 1) == 0) &&
  946. (*(*(null_buf + i + 1) + j - 1) == 0.0)) {
  947. /*printf("IN NOT DONE i=%d j=%d i=%d j=%d buf=%f patchmap=%d null_buf=%f\n",
  948. i,j,i+1,j-1,*(*(buf + i + 1) + j - 1),*(*(patchmap + i + 1) + j - 1),
  949. *(*(null_buf + i + 1) + j - 1)); */
  950. not_done = 1;
  951. }
  952. }
  953. }
  954. /* if there is no neighboring pixel with the
  955. same class, then stop tracing */
  956. else
  957. not_done = 0;
  958. } /*2 */
  959. /* STEP 2: CLEAN AND FILL THE PATCH WITHIN
  960. ITS BOUNDARIES. THE MAP IS CLEANED AND
  961. FILLED INTO "PATCHMAP" WHICH THEN CONTAINS
  962. THE FOLLOWING VALUES:
  963. 1 = BOUNDARY PT
  964. -999 = INTERIOR (NON BOUNDARY) PT */
  965. for (i = patch->n; i < patch->s + 1; i++) { /*3 */
  966. /* find the westernmost and easternmost boundary
  967. points in row i */
  968. roww = patch->w;
  969. rowe = patch->e;
  970. while (*(*(patchmap + i) + roww) == 0 && roww < patch->e)
  971. roww++;
  972. while (*(*(patchmap + i) + rowe) == 0 && rowe > patch->w)
  973. rowe--;
  974. /* if the westernmost and easternmost boundary
  975. pts in row i are not the same or are not
  976. next to each other, then we need to scan
  977. across row i */
  978. if (roww != rowe && roww + 1 != rowe) { /*4 */
  979. for (j = roww; j < rowe; j++) { /*5 */
  980. /* if this pixel is one of the traced boundary
  981. or interior pts and the next pixel in the row
  982. is not one of these or has not been traced, */
  983. if (*(*(patchmap + i) + j) != 0 && *(*(patchmap + i) + j + 1) == 0) { /*6 */
  984. /* if the next pixel has the same class, then
  985. give that pixel a -999 in patchmap to signify
  986. that it is part of the patch, and make null_buf
  987. a 1.0 to signify that this next pixel has been
  988. traced */
  989. if (*(*(buf + i) + j + 1) == class) {
  990. *(*(patchmap + i) + j + 1) = -999;
  991. *(*(null_buf + i) + j + 1) = 1.0;
  992. }
  993. /* but if the next pixel doesn't have the same
  994. class, then the present pixel marks the edge
  995. of a potential interior boundary for the patch.
  996. Trace this boundary only if it has not already
  997. been traced */
  998. else if (*(*(buf + i) + j + 1) != class && (*(*(patchmap + i) + j) != 1 || *(*(patchmap + i) + j + 1) == 0)) { /*7 */
  999. not_done = 1;
  1000. row1 = p = i;
  1001. col1 = q = j;
  1002. di2 = 0;
  1003. dj2 = 1;
  1004. while (not_done) { /*8 */
  1005. if (*(*(patchmap + p) + q) == -999)
  1006. *(*(patchmap + p) + q) = 4;
  1007. if (*(*(patchmap + p) + q) == 4) {
  1008. ptrnew = (PT *) G_calloc(1, sizeof(PT));
  1009. ptrthis = ptrfirst;
  1010. while (ptrthis->next != (PT *) NULL)
  1011. ptrthis = ptrthis->next;
  1012. ptrthis->next = ptrnew;
  1013. ptrthis = ptrnew;
  1014. ptrthis->row = p;
  1015. ptrthis->col = q;
  1016. *(*(patchmap + p) + q) = 1;
  1017. *(*(null_buf + p) + q) = 1.0;
  1018. pts++;
  1019. }
  1020. if (yes_nb(&di2, &dj2, buf, class, p, q,
  1021. nrows, ncols)) {
  1022. p = p + di2;
  1023. q = q + dj2;
  1024. if (*(*(patchmap + p) + q) != 1) {
  1025. *(*(patchmap + p) + q) = 4;
  1026. *(*(null_buf + p) + q) = 1.0;
  1027. }
  1028. di2 = -di2;
  1029. dj2 = -dj2;
  1030. clockwise(&di2, &dj2);
  1031. if (p == row1 && q == col1) {
  1032. not_done = 0;
  1033. }
  1034. }
  1035. else
  1036. not_done = 0;
  1037. } /*8 */
  1038. } /*7 */
  1039. } /*6 */
  1040. } /*5 */
  1041. } /*4 */
  1042. } /*3 */
  1043. /* STEP 3: GO THROUGH THE RESULTING PATCHMAP
  1044. AND FIND THE INTERIOR & EDGE AREA IF REQUESTED */
  1045. if (choice->core[0]) {
  1046. for (k = 0; k < choice->edge; k++) {
  1047. for (i = patch->n; i < patch->s + 1; i++) {
  1048. for (j = patch->w; j < patch->e + 1; j++) {
  1049. if ((k > 0 && *(*(patchmap + i) + j) == k) ||
  1050. (k == 0 && *(*(patchmap + i) + j) == 1)) {
  1051. /* if the sampling area border is not to
  1052. be considered patch edge and we're
  1053. interior of the sampling area border,
  1054. then we can search for interior; OR if the
  1055. sampling area border is to be considered
  1056. patch edge, then we can search for interior */
  1057. if ((choice->perim2 && i != 1 && i != nrows &&
  1058. j != 1 && j != ncols) || !choice->perim2) {
  1059. di = 0;
  1060. dj = -1;
  1061. for (m = 0; m < 8; m++) {
  1062. if (*(*(patchmap + i + di) + j + dj) ==
  1063. -999) {
  1064. if (choice->trace) {
  1065. if (k > 0)
  1066. *(*(patchmap + i + di) + j +
  1067. dj) = k + 1;
  1068. }
  1069. else if (di == 0 || dj == 0) {
  1070. if (k > 0)
  1071. *(*(patchmap + i + di) + j +
  1072. dj) = k + 1;
  1073. }
  1074. }
  1075. clockwise(&di, &dj);
  1076. }
  1077. }
  1078. else {
  1079. nozero = 1;
  1080. if (j != 1)
  1081. if (*(*(patchmap + i) + j - 1) == 0)
  1082. nozero = 0;
  1083. if (i != 1 && j != 1)
  1084. if (*(*(patchmap + i - 1) + j - 1) == 0)
  1085. nozero = 0;
  1086. if (i != 1)
  1087. if (*(*(patchmap + i - 1) + j) == 0)
  1088. nozero = 0;
  1089. if (i != 1 && j != ncols)
  1090. if (*(*(patchmap + i - 1) + j + 1) == 0)
  1091. nozero = 0;
  1092. if (j != ncols)
  1093. if (*(*(patchmap + i) + j + 1) == 0)
  1094. nozero = 0;
  1095. if (i != nrows && j != ncols)
  1096. if (*(*(patchmap + i + 1) + j + 1) == 0)
  1097. nozero = 0;
  1098. if (i != nrows)
  1099. if (*(*(patchmap + i + 1) + j) == 0)
  1100. nozero = 0;
  1101. if (i != nrows && j != 1)
  1102. if (*(*(patchmap + i + 1) + j - 1) == 0)
  1103. nozero = 0;
  1104. if (nozero)
  1105. *(*(patchmap + i) + j) = -999;
  1106. }
  1107. }
  1108. }
  1109. }
  1110. }
  1111. }
  1112. /* STEP 4: GO THROUGH THE RESULTING PATCHMAP AND DETERMINE
  1113. THE PATCH SIZE, AMOUNT OF PERIMETER AND, IF REQUESTED,
  1114. THE CORE SIZE AND EDGE SIZE */
  1115. area = 0;
  1116. per = 0;
  1117. corearea = 0;
  1118. edgearea = 0;
  1119. for (i = patch->n; i < patch->s + 1; i++) {
  1120. for (j = patch->w; j < patch->e + 1; j++) {
  1121. if (*(*(patchmap + i) + j) || *(*(patchmap + i) + j) == -999) {
  1122. area++;
  1123. if (choice->perim2 == 0) {
  1124. if (j == 1 || j == ncols)
  1125. per++;
  1126. }
  1127. if (j < ncols && *(*(patchmap + i) + j + 1) == 0)
  1128. per++;
  1129. if (j > 1 && *(*(patchmap + i) + j - 1) == 0)
  1130. per++;
  1131. /* if a num map was requested with the -n flag,
  1132. then copy the patch numbers into pat array */
  1133. if (choice->patchmap)
  1134. *(*(pat + i) + j) = patch->num;
  1135. /* if core calculations are requested */
  1136. if (choice->core[0]) {
  1137. if (*(*(patchmap + i) + j) == -999)
  1138. corearea++;
  1139. if (*(*(patchmap + i) + j) > 0)
  1140. edgearea++;
  1141. }
  1142. /* if core map is requested */
  1143. if (choice->coremap) {
  1144. if (*(*(patchmap + i) + j) == -999)
  1145. *(*(cor + i) + j) = *(*(buf + i) + j);
  1146. }
  1147. }
  1148. }
  1149. }
  1150. for (j = patch->w; j < patch->e + 1; j++) {
  1151. for (i = patch->n; i < patch->s + 1; i++) {
  1152. if (*(*(patchmap + i) + j) || *(*(patchmap + i) + j) == -999) {
  1153. if (choice->perim2 == 0) {
  1154. if (i == 1 || i == nrows)
  1155. per++;
  1156. }
  1157. if (i < nrows && *(*(patchmap + i + 1) + j) == 0)
  1158. per++;
  1159. if (i > 1 && *(*(patchmap + i - 1) + j) == 0)
  1160. per++;
  1161. }
  1162. }
  1163. }
  1164. patch->area = area;
  1165. patch->perim = per;
  1166. patch->edge = edgearea;
  1167. patch->core = corearea;
  1168. /* STEP 5: GO THROUGH THE RESULTING LIST OF PTS,
  1169. RECORD THE ROW AND COL IN THE PATCH
  1170. STRUCTURE, AND FIND THE LONG AXIS AND
  1171. CENTER OF THE PATCH */
  1172. patch->npts = pts;
  1173. /* allocate enough memory to store the list of
  1174. pts in the PATCH structure */
  1175. patch->col = (int *)G_calloc(pts, sizeof(int));
  1176. patch->row = (int *)G_calloc(pts, sizeof(int));
  1177. /* go through the list of pts */
  1178. i = 0;
  1179. ptrthis = ptrfirst;
  1180. while (ptrthis) {
  1181. ptrfree = ptrthis;
  1182. /* save the pt locat. in the PATCH structure */
  1183. *(patch->row + i) = ptrthis->row;
  1184. *(patch->col + i) = ptrthis->col;
  1185. /* long-axis step 1: find the largest
  1186. sum of squares between patch boundary
  1187. pts if the Related Circumscribing Circle
  1188. shape index is requested */
  1189. if (choice->Mx[3]) {
  1190. if (pts == 1) {
  1191. lng = 2;
  1192. }
  1193. else {
  1194. for (j = 0; j < i + 1; j++) {
  1195. if ((tmp =
  1196. (abs(*(patch->row + j) - *(patch->row + i)) +
  1197. 1) * (abs(*(patch->row + j) -
  1198. *(patch->row + i)) + 1) +
  1199. (abs(*(patch->col + j) - *(patch->col + i)) +
  1200. 1) * (abs(*(patch->col + j) -
  1201. *(patch->col + i)) + 1)) > lng)
  1202. lng = tmp;
  1203. }
  1204. }
  1205. }
  1206. /* patch center step 1: sum up the boundary
  1207. coordinates */
  1208. if (i < pts) {
  1209. patch->c_row += *(patch->row + i);
  1210. patch->c_col += *(patch->col + i);
  1211. }
  1212. ptrthis = ptrthis->next;
  1213. G_free(ptrfree);
  1214. i++;
  1215. }
  1216. /* patch long axis and center step 2: complete
  1217. the calculations */
  1218. if (choice->Mx[3])
  1219. patch->long_axis = sqrt((double)(lng));
  1220. patch->c_col = (int)(patch->c_col / pts + 0.5);
  1221. patch->c_row = (int)(patch->c_row / pts + 0.5);
  1222. /* STEP 6: IF TWIST STATISTICS WERE REQUESTED, GO
  1223. THROUGH THE PATCHMAP AND CALCULATE TWIST & OMEGA */
  1224. if (choice->boundary[0]) {
  1225. /* dynamically allocate storage for the arrays that will
  1226. hold the twist tallies and P values */
  1227. trows = patch->s - patch->n + 3;
  1228. tcols = patch->e - patch->w + 3;
  1229. twist2 = (int ***)G_calloc(trows + 3, sizeof(int **));
  1230. for (i = 0; i < trows + 3; i++) {
  1231. twist2[i] = (int **)G_calloc(tcols + 3, sizeof(int *));
  1232. for (j = 0; j < tcols + 3; j++)
  1233. twist2[i][j] = (int *)G_calloc(7, sizeof(int));
  1234. }
  1235. twistP = (float ***)G_calloc(trows + 3, sizeof(float **));
  1236. for (i = 0; i < trows + 3; i++) {
  1237. twistP[i] = (float **)G_calloc(tcols + 3, sizeof(float *));
  1238. for (j = 0; j < tcols + 3; j++)
  1239. twistP[i][j] = (float *)G_calloc(7, sizeof(float));
  1240. }
  1241. /* zero the twist2 and twistP matrices */
  1242. for (i = 0; i < trows + 3; i++) {
  1243. for (j = 0; j < tcols + 3; j++) {
  1244. for (k = 0; k < 5; k++) {
  1245. twist2[i][j][k] = 0;
  1246. twistP[i][j][k] = 0.0;
  1247. }
  1248. }
  1249. }
  1250. /* fill the twist2 matrix with counts; do this for
  1251. each pixel in the patch, identified by having a
  1252. value of 1 or -999 */
  1253. for (i = patch->n; i < patch->s + 1; i++) {
  1254. for (j = patch->w; j < patch->e + 1; j++) {
  1255. n = i - patch->n + 1;
  1256. e = j - patch->w + 1;
  1257. if (*(*(patchmap + i) + j) > 0 ||
  1258. *(*(patchmap + i) + j) == -999) {
  1259. if (*(*(patchmap + i) + j - 1) > 0 ||
  1260. *(*(patchmap + i) + j - 1) == -999)
  1261. twist2[n][e][0]++;
  1262. if (*(*(patchmap + i - 1) + j - 1) > 0 ||
  1263. *(*(patchmap + i - 1) + j - 1) == -999)
  1264. twist2[n][e][0]++;
  1265. if (*(*(patchmap + i - 1) + j) > 0 ||
  1266. *(*(patchmap + i - 1) + j) == -999)
  1267. twist2[n][e][0]++;
  1268. if (*(*(patchmap + i - 1) + j) > 0 ||
  1269. *(*(patchmap + i - 1) + j) == -999)
  1270. twist2[n][e][1]++;
  1271. if (*(*(patchmap + i - 1) + j + 1) > 0 ||
  1272. *(*(patchmap + i - 1) + j + 1) == -999)
  1273. twist2[n][e][1]++;
  1274. if (*(*(patchmap + i) + j + 1) > 0 ||
  1275. *(*(patchmap + i) + j + 1) == -999)
  1276. twist2[n][e][1]++;
  1277. if (*(*(patchmap + i) + j + 1) > 0 ||
  1278. *(*(patchmap + i) + j + 1) == -999)
  1279. twist2[n][e][2]++;
  1280. if (*(*(patchmap + i + 1) + j + 1) > 0 ||
  1281. *(*(patchmap + i + 1) + j + 1) == -999)
  1282. twist2[n][e][2]++;
  1283. if (*(*(patchmap + i + 1) + j) > 0 ||
  1284. *(*(patchmap + i + 1) + j) == -999)
  1285. twist2[n][e][2]++;
  1286. if (*(*(patchmap + i + 1) + j) > 0 ||
  1287. *(*(patchmap + i + 1) + j) == -999)
  1288. twist2[n][e][3]++;
  1289. if (*(*(patchmap + i + 1) + j - 1) > 0 ||
  1290. *(*(patchmap + i + 1) + j - 1) == -999)
  1291. twist2[n][e][3]++;
  1292. if (*(*(patchmap + i) + j - 1) > 0 ||
  1293. *(*(patchmap + i) + j - 1) == -999)
  1294. twist2[n][e][3]++;
  1295. /* calculate the P values based on the tallies */
  1296. for (k = 0; k < 4; k++) {
  1297. if (*(*(patchmap + i) + j) > 0 ||
  1298. *(*(patchmap + i) + j) == -999) {
  1299. if (twist2[n][e][k] - 1 < 0)
  1300. twistP[n][e][k] = 1.0;
  1301. else if (twist2[n][e][k] - 1 == 0) {
  1302. if (k - 1 > 0)
  1303. a = i + 1;
  1304. else
  1305. a = i - 1;
  1306. if (k == 1 || k == 2)
  1307. b = j + 1;
  1308. else
  1309. b = j - 1;
  1310. if (*(*(patchmap + a) + b) > 0 ||
  1311. *(*(patchmap + a) + b) == -999)
  1312. twistP[n][e][k] = 1.0;
  1313. else
  1314. twistP[n][e][k] = 0.0;
  1315. }
  1316. else if (twist2[n][e][k] - 1 > 0) {
  1317. if (twist2[n][e][k] == 3)
  1318. twistP[n][e][k] = 0.0;
  1319. else if (twist2[n][e][k] == 2)
  1320. twistP[n][e][k] = .33333;
  1321. }
  1322. }
  1323. }
  1324. }
  1325. }
  1326. }
  1327. /* sum up the P values to calculate the twist number */
  1328. sumT = 0.0;
  1329. for (n = 0; n < trows; n++) {
  1330. for (e = 0; e < tcols; e++) {
  1331. for (k = 0; k < 4; k++)
  1332. sumT = sumT + twistP[n][e][k];
  1333. }
  1334. }
  1335. patch->twist = (int)(sumT + 0.5);
  1336. /* calculate the omega index for 3 cases, depending upon
  1337. whether 8-neighbor or 4-neighbor tracing was chosen */
  1338. if (choice->trace) {
  1339. if (patch->area > 1.0)
  1340. patch->omega = (4.0 * patch->area - (float)patch->twist) /
  1341. (4.0 * patch->area - 4.0);
  1342. else
  1343. patch->omega = 0.0;
  1344. }
  1345. else {
  1346. if ((((int)patch->area % 4) - 1) == 0) {
  1347. if (patch->area > 1.0)
  1348. patch->omega =
  1349. (2.0 * patch->area + 2.0 -
  1350. (float)patch->twist) / (2.0 * patch->area - 2.0);
  1351. else
  1352. patch->omega = 0.0;
  1353. }
  1354. else
  1355. patch->omega = (2.0 * patch->area - (float)patch->twist) /
  1356. (2.0 * patch->area - 4.0);
  1357. }
  1358. /*printf("twistnum = %4d omega=%6.4f area=%7.0f\n", patch->twist,
  1359. patch->omega,patch->area); */
  1360. /* free memory allocated for holding twist tallies and
  1361. P values */
  1362. for (i = 0; i < trows + 3; i++) {
  1363. for (j = 0; j < tcols + 3; j++)
  1364. G_free(twistP[i][j]);
  1365. G_free(twistP[i]);
  1366. }
  1367. G_free(twistP);
  1368. for (i = 0; i < trows + 3; i++) {
  1369. for (j = 0; j < tcols + 3; j++)
  1370. G_free(twist2[i][j]);
  1371. G_free(twist2[i]);
  1372. }
  1373. G_free(twist2);
  1374. }
  1375. /* STEP 7: MAKE NEXT PATCH NULL, FREE MEMORY,
  1376. AND RETURN THE PATCH STRUCTURE */
  1377. patch->next = (PATCH *) NULL;
  1378. /* free the memory allocated for patchmap */
  1379. for (i = 0; i < nrows + 3; i++)
  1380. G_free(patchmap[i]);
  1381. G_free(patchmap);
  1382. /* send the patch info back to trace */
  1383. return (patch);
  1384. } /*1 */
  1385. }
  1386. /* SEARCH THE 8 NEIGHBORS OF A PIXEL IN
  1387. THE BUFFER IN A CLOCKWISE DIRECTION
  1388. LOOKING FOR A PIXEL WITH THE SAME
  1389. CLASS AND RETURN A 1 AND DI, DJ FOR
  1390. THE FIRST PIXEL FOUND; OTHERWISE RETURN
  1391. A ZERO */
  1392. int yes_nb(int *di, int *dj, DCELL ** buf, double class, int i, int j,
  1393. int nrows, int ncols)
  1394. {
  1395. /* di=0 to start; di is the value to be added to i to get to the
  1396. pixel with the same value
  1397. dj=-1 to start; dj is the value to be added to j to get to the
  1398. pixel with the same value
  1399. class = the attribute of the center pixel
  1400. */
  1401. register int k;
  1402. /*printf("1i=%d di=%d j=%d dj=%d nrows=%d
  1403. ncols=%d\n",i,*di,j,*dj,nrows,ncols); */
  1404. /* if tracing is to include crossing to
  1405. diagonal pixels */
  1406. if (choice->trace) { /*1 */
  1407. /* search through the 8 neighbor pixels */
  1408. for (k = 0; k < 8; k++) {
  1409. /* if the neighbor pixel has the same
  1410. attribute as that of the current pixel,
  1411. then it may be part of the patch.
  1412. Confine the search to only pixels
  1413. inside the buffer to avoid a crash! */
  1414. if ((i + *di > 0) && (j + *dj > 0) &&
  1415. (i + *di <= nrows) && (j + *dj <= ncols)) {
  1416. if (class == *(*(buf + i + *di) + j + *dj))
  1417. return 1;
  1418. }
  1419. clockwise(di, dj);
  1420. }
  1421. /* if no neighbor with the same class is found,
  1422. then we are done tracing the patch */
  1423. return 0;
  1424. } /*1 */
  1425. /* if tracing is not to include crossing to
  1426. diagonal pixels */
  1427. else {
  1428. /* search through the 8 neighbor pixels */
  1429. for (k = 0; k < 8; k++) {
  1430. /* if the neighbor pixel has the same
  1431. attribute as that of the current pixel,
  1432. then maybe it is part of the same patch */
  1433. if ((i + *di > 0) && (j + *dj > 0) &&
  1434. (i + *di <= nrows) && (j + *dj <= ncols)) {
  1435. if (class == *(*(buf + i + *di) + j + *dj)) {
  1436. /* if the neighbor pixel is directly above,
  1437. below, to the right or left of the current
  1438. pixel then tracing can continue */
  1439. if (*di == 0 || *dj == 0)
  1440. return 1;
  1441. /* next check the diagonal neighbors
  1442. that have a bishops pattern and if
  1443. they have an adjacent pixel with the same
  1444. class then continue tracing, as they are
  1445. not isolated diagonal pixels */
  1446. /* lower left bishops pattern */
  1447. if (*di == 1 && *dj == -1)
  1448. if ((class == *(*(buf + i + *di) + j)) ||
  1449. (class == *(*(buf + i) + j + *dj)))
  1450. return 1;
  1451. /* upper left bishops pattern */
  1452. if (*di == -1 && *dj == -1)
  1453. if ((class == *(*(buf + i + *di) + j)) ||
  1454. (class == *(*(buf + i) + j + *dj)))
  1455. return 1;
  1456. /* upper right bishops pattern */
  1457. if (*di == -1 && *dj == 1)
  1458. if ((class == *(*(buf + i + *di) + j)) ||
  1459. (class == *(*(buf + i) + j + *dj)))
  1460. return 1;
  1461. /* lower right bishops pattern */
  1462. if (*di == 1 && *dj == 1)
  1463. if ((class == *(*(buf + i + *di) + j)) ||
  1464. (class == *(*(buf + i) + j + *dj)))
  1465. return 1;
  1466. }
  1467. }
  1468. /* if the neighbor pixel has a different
  1469. class or it is not in the
  1470. same row or col and is an isolated
  1471. bishops pattern pixel, then don't
  1472. trace it, but go to the next one
  1473. of the 8 neighbors */
  1474. clockwise(di, dj);
  1475. }
  1476. /* if all the neighbors are isolated
  1477. bishops pattern pixels or no
  1478. neighbor with the same class is found
  1479. then we are done tracing the patch */
  1480. return (0);
  1481. }
  1482. }
  1483. /* CIRCLE CLOCKWISE AROUND THE CURRENT PT */
  1484. void clockwise(int *i, int *j)
  1485. {
  1486. if (*i != 0 && *j != -*i)
  1487. *j -= *i;
  1488. else
  1489. *i += *j;
  1490. return;
  1491. }