main.c 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646
  1. /*
  2. ************************************************************
  3. * MODULE: r.le.trace/main.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 obtain basic information about patches in a *
  10. * landscape by pointing at them in the display *
  11. * *
  12. * COPYRIGHT: (C) 2001 by W.L. Baker *
  13. * *
  14. * This program is free software under the GNU General *
  15. * Public License(>=v2). Read the file COPYING that comes *
  16. * with GRASS for details *
  17. * *
  18. ************************************************************/
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <unistd.h>
  23. #include <grass/config.h>
  24. #include <grass/gis.h>
  25. #include <grass/display.h>
  26. #include <grass/glocale.h>
  27. #include "r.le.trace.h"
  28. #include "local_proto.h"
  29. struct CHOICE *choice;
  30. int finput;
  31. int total_patches = 0;
  32. PATCH *patch_list = NULLPTR;
  33. FILE *fp;
  34. /* MAIN PROGRAM */
  35. int main(int argc, char *argv[])
  36. {
  37. struct GModule *module;
  38. struct Cell_head window;
  39. int bot, right, t0, b0, l0, r0, clear = 0;
  40. double Rw_l, Rscr_wl;
  41. void set_map();
  42. setbuf(stdout, NULL); /* unbuffered */
  43. setbuf(stderr, NULL);
  44. G_gisinit(argv[0]);
  45. choice = (struct CHOICE *)G_calloc(1, sizeof(struct CHOICE));
  46. module = G_define_module();
  47. G_add_keyword(_("raster"));
  48. module->description =
  49. _("Displays the boundary of each r.le patch and shows how the boundary "
  50. "is traced, displays the attribute, size, perimeter and shape "
  51. "indices for each patch and saves the data in an output file.");
  52. user_input(argc, argv);
  53. /* setup the current window for display */
  54. G_system("d.frame -e");
  55. Rw_l = (double)Rast_window_cols() / Rast_window_rows();
  56. R_open_driver();
  57. R_font("romant");
  58. G_get_set_window(&window);
  59. t0 = R_screen_top();
  60. b0 = R_screen_bot();
  61. l0 = R_screen_left();
  62. r0 = R_screen_rite();
  63. Rscr_wl = (double)(r0 - l0) / (b0 - t0);
  64. if (Rscr_wl > Rw_l) {
  65. bot = b0;
  66. right = l0 + (b0 - t0) * Rw_l;
  67. }
  68. else {
  69. right = r0;
  70. bot = t0 + (r0 - l0) / Rw_l;
  71. }
  72. D_setup(clear);
  73. D_new_window("a", t0, bot, l0, right);
  74. D_set_cur_wind("a");
  75. D_show_window(D_translate_color("green"));
  76. R_set_window(t0, bot, l0, right);
  77. R_font("cyrilc");
  78. R_text_size(8, 8);
  79. R_close_driver();
  80. /* invoke the setup modules */
  81. if (strcmp(choice->out, ""))
  82. set_map(choice->fn, window, t0, bot, l0, right, choice->out);
  83. else
  84. set_map(choice->fn, window, t0, bot, l0, right, NULL);
  85. G_free(choice);
  86. return (EXIT_SUCCESS);
  87. }
  88. /* DISPLAY A MESSAGE AND THE MAP, THEN
  89. TRACE THE PATCHES AND DISPLAY THEM */
  90. void set_map(char *name, struct Cell_head window, int top, int bot, int left,
  91. int right, char *fn)
  92. {
  93. char cmd[30];
  94. double msc[2];
  95. void scr_cell(), cell_clip_drv(), show_patch();
  96. /* display a message and the map */
  97. G_system("clear");
  98. puts("\n\nR.LE.TRACE IS WORKING...\n");
  99. G_system("d.erase");
  100. sprintf(cmd, "d.rast %s", name);
  101. G_system(cmd);
  102. /* setup the screen-cell array coordinate
  103. system conversion */
  104. scr_cell(&window, top, bot, left, right, msc);
  105. /* call the cell clip driver to trace the
  106. patches in the window */
  107. cell_clip_drv(0, 0, window.cols, window.rows, NULL, 0);
  108. /* show the patches */
  109. show_patch(fn, msc, cmd);
  110. }
  111. /* DISPLAY THE PATCH INFORMATION */
  112. void show_patch(char *fn, double *msc, char *cmd)
  113. {
  114. PATCH *tmp, *tmp0;
  115. int num;
  116. char c;
  117. void draw_patch(), patch_attr();
  118. if (!total_patches)
  119. return;
  120. if (G_yes("\n\nShow patch numbers on the display? ", 1)) {
  121. tmp = patch_list;
  122. while (tmp) {
  123. if (tmp)
  124. draw_patch(tmp, msc);
  125. tmp = tmp->next;
  126. }
  127. }
  128. if (G_yes("\n\nShow data for a patch, identified by number? ", 1)) {
  129. for (;;) {
  130. fprintf(stderr,
  131. "\n\nWhich patch number? Enter zero to continue: ");
  132. fscanf(stdin, "%d", &num);
  133. if (num == 0)
  134. break;
  135. rewind(stdin);
  136. if (num < 0)
  137. num = -num;
  138. tmp = patch_list;
  139. while (tmp && tmp->num != num)
  140. tmp = tmp->next;
  141. if (tmp) {
  142. draw_patch(tmp, msc);
  143. patch_attr(fp, tmp, 1);
  144. }
  145. else {
  146. G_warning("\nThe patch is not in the patch-list.\n");
  147. G_sleep(1);
  148. }
  149. }
  150. }
  151. if (fn) {
  152. fn[strlen(fn)] = '\0';
  153. if (!(fp = fopen(fn, "w")))
  154. G_fatal_error("Can't open file to write, exit.");
  155. }
  156. if (G_yes("", 1)) ;
  157. G_system("clear");
  158. fprintf(stderr, "In the following choice, if an output file was");
  159. fprintf(stderr, "\nchosen, then data can be shown on screen and");
  160. fprintf(stderr, "\nwritten to that file. Otherwise, data can");
  161. fprintf(stderr, "\njust be shown on screen");
  162. if (G_yes("\n\nShow data for some patches in sequence (y)\
  163. \nor show data for all patches (n)? ", 1)) {
  164. tmp = patch_list;
  165. while (tmp) {
  166. puts("\n <CR> - Show next patch; don't refresh display. ");
  167. puts(" n - Show next patch and refresh display.");
  168. puts(" s - Skip one patch and refresh display.");
  169. puts(" q - Quit.");
  170. c = getchar();
  171. if (c == 's' || c == 'n' || c == 'q') {
  172. if (c == 's') {
  173. getchar();
  174. tmp = tmp->next;
  175. G_system("d.erase");
  176. G_system(cmd);
  177. }
  178. else if (c == 'q') {
  179. G_system("d.frame -e");
  180. exit(0);
  181. }
  182. else if (c == 'n') {
  183. getchar();
  184. G_system("d.erase");
  185. G_system(cmd);
  186. }
  187. }
  188. draw_patch(tmp, msc);
  189. patch_attr(fp, tmp, 1);
  190. tmp0 = tmp;
  191. tmp = tmp->next;
  192. G_free(tmp0->row);
  193. G_free(tmp0->col);
  194. G_free(tmp0);
  195. }
  196. }
  197. else {
  198. tmp = patch_list;
  199. if (G_yes("\n\nOutput data for all patches on screen (y) or just\
  200. \nto the output file (n)? ", 1)) {
  201. while (tmp) {
  202. patch_attr(fp, tmp, 1);
  203. tmp0 = tmp;
  204. tmp = tmp->next;
  205. G_free(tmp0->row);
  206. G_free(tmp0->col);
  207. G_free(tmp0);
  208. }
  209. }
  210. else {
  211. while (tmp) {
  212. patch_attr(fp, tmp, 0);
  213. tmp0 = tmp;
  214. tmp = tmp->next;
  215. G_free(tmp0->row);
  216. G_free(tmp0->col);
  217. G_free(tmp0);
  218. }
  219. }
  220. }
  221. if (fn)
  222. fclose(fp);
  223. }
  224. /* DISPLAY PATCH ATTRIBUTES ON THE SCREEN */
  225. void patch_attr(FILE * fp, PATCH * p, int show)
  226. {
  227. double shp1, shp2, shp3;
  228. if (p->area) {
  229. shp1 = p->perim / p->area;
  230. shp2 = 0.282 * p->perim / sqrt(p->area);
  231. }
  232. else {
  233. shp1 = 0.0;
  234. shp2 = 0.0;
  235. }
  236. if (p->long_axis)
  237. shp3 = 2.0 * sqrt(p->area / M_PI) / p->long_axis;
  238. else
  239. shp3 = 0.0;
  240. if (!show)
  241. goto skip;
  242. fprintf(stderr, "\nPatch %d of %d total patches:\n", p->num,
  243. total_patches);
  244. fprintf(stderr, " Attribute = %11.3f\n", p->att);
  245. fprintf(stderr, " Area (pixels) = %11.0f\n", p->area);
  246. fprintf(stderr, " Perimeter (pixels) = %11.0f\n", p->perim);
  247. fprintf(stderr, " Shape: P/A = %11.3f\n", shp1);
  248. fprintf(stderr, " Shape: CP/A = %11.3f\n", shp2);
  249. fprintf(stderr, " Shape: RCC = %11.3f\n", shp3);
  250. fprintf(stderr, " Twist No. = %11d\n", p->twist);
  251. fprintf(stderr, " Omega Index = %11.3f\n", p->omega);
  252. skip:
  253. if (!fp)
  254. return;
  255. if (p->num == 1) {
  256. fprintf(fp,
  257. "Patch Patch Patch Patch ----Shape Index---- Twist Omega\n");
  258. fprintf(fp,
  259. "Number Attr. Area Perim. P/A CP/A RCC Number Index\n");
  260. }
  261. fprintf(fp, "%6d %12.3f %7.0f %7.0f %7.3f %7.3f %7.3f %6d %6.3f\n",
  262. p->num, p->att, p->area, p->perim, shp1, shp2, shp3, p->twist,
  263. p->omega);
  264. }
  265. /* PLACE PATCH NUMBERS ON THE SCREEN */
  266. void draw_patch(PATCH * p, double *m)
  267. {
  268. register int i;
  269. int r0, c0, r1, c1;
  270. char number[10];
  271. void draw_cross();
  272. G_sleep_on_error(0);
  273. R_open_driver();
  274. R_standard_color(D_translate_color("black"));
  275. r1 = p->c_row * m[1] - 0.5 * m[1];
  276. c1 = p->c_col * m[0] - 0.5 * m[0];
  277. R_move_abs(c1, r1);
  278. sprintf(number, "%d", p->num);
  279. R_text_size(10, 10);
  280. R_text(number);
  281. R_close_driver();
  282. }
  283. /* SETUP THE CONVERSION BETWEEN SCREEN AND
  284. ARRAY SYSTEMS */
  285. void scr_cell(struct Cell_head *wind, int top, int bot, int left, int right,
  286. double *m)
  287. {
  288. m[0] = (right - left) / (double)wind->cols;
  289. m[1] = (bot - top) / (double)wind->rows;
  290. }
  291. /* DRIVER FOR CELL CLIPPING, TRACING,
  292. AND CALCULATIONS */
  293. void cell_clip_drv(int col0, int row0, int ncols, int nrows, double **value,
  294. int index)
  295. {
  296. CELL **pat, *pat_buf;
  297. DCELL **buf;
  298. DCELL **null_buf;
  299. int i, j, fd, fe, p, infd, x, centernull = 0;
  300. int hist_ok, colr_ok, cats_ok, range_ok;
  301. char *mapset, *name;
  302. PATCH *list_head;
  303. struct History hist;
  304. struct Categories cats;
  305. struct Categories newcats;
  306. struct Cell_stats stats;
  307. struct Colors colr;
  308. struct Cell_head cellhd;
  309. struct Range range;
  310. struct FPRange fprange;
  311. struct Quant quant;
  312. RASTER_MAP_TYPE data_type;
  313. /*
  314. Variables:
  315. EXTERN:
  316. finput = the input raster map
  317. patch_list = the patch list
  318. IN:
  319. col0 = starting column for area to be clipped
  320. row0 = starting row for area to be clipped
  321. ncols = number of columns in area to be clipped
  322. nrows = number of rows in area to be clipped
  323. value = array containing a full row of the results of the moving
  324. window for all the chosen measures if a moving window map,
  325. otherwise 0
  326. index = number of the region to be clipped, if there's a region map,
  327. number of the column if a moving window
  328. INTERNAL:
  329. pat = pointer to array containing the map of patch numbers; this map
  330. can only be integer
  331. pat_buf = row buffer to temporarily hold results for patch number map
  332. buf = pointer to array containing the clipped area, a smaller area
  333. than the original raster map to be read from finput; this map
  334. can be integer, floating point, or double, but is stored as a
  335. double throughout the program
  336. null_buf = pointer to array containing 0.0 if pixel in input raster map is
  337. not null and 1.0 if pixel in input raster map is null
  338. infd = pointer to file with map of patches
  339. i, j = counts the row and column when going through arrays
  340. p = counts the number of measures in
  341. fd = pointer to file to hold patch number map
  342. fe = pointer to file to hold patch interior map
  343. mapset = the name of the mapset for the raster map being analyzed
  344. name = the name of the raster map being analyzed
  345. list_head = point to the patch list
  346. */
  347. pat = NULL;
  348. total_patches = 0;
  349. name = choice->fn;
  350. mapset = G_find_raster2(name, "");
  351. data_type = Rast_map_type(name, mapset);
  352. /* dynamically allocate storage for the
  353. buffer that will hold the contents of
  354. the clipped area */
  355. buf = (DCELL **) G_calloc(nrows + 3, sizeof(DCELL *));
  356. for (i = 0; i < nrows + 3; i++) {
  357. buf[i] = (DCELL *) Rast_allocate_buf(DCELL_TYPE);
  358. }
  359. /* dynamically allocate storage for the
  360. buffer that will hold the null values for
  361. the clipped area */
  362. null_buf = (DCELL **) G_calloc(nrows + 3, sizeof(DCELL *));
  363. for (i = 0; i < nrows + 3; i++)
  364. null_buf[i] = (DCELL *) Rast_allocate_buf(DCELL_TYPE);
  365. /* clip out the sampling area */
  366. cell_clip(buf, null_buf, row0, col0, nrows, ncols, index, &centernull);
  367. /* if the clipped area is not all null values
  368. trace the patches in the sampling area; if
  369. a moving window is used, then the center
  370. pixel must also not be null */
  371. trace(nrows, ncols, buf, null_buf, pat);
  372. /* free memory allocated for content buffer */
  373. for (i = 0; i < nrows + 3; i++)
  374. G_free(buf[i]);
  375. G_free(buf);
  376. /* free memory allocated for null buffer */
  377. for (i = 0; i < nrows + 3; i++)
  378. G_free(null_buf[i]);
  379. G_free(null_buf);
  380. /* free memory allocated for patch list */
  381. /* if (total_patches) {
  382. list_head = patch_list;
  383. while(list_head) {
  384. G_free (list_head->col);
  385. G_free (list_head->row);
  386. G_free (list_head);
  387. list_head = list_head->next;
  388. }
  389. }
  390. */
  391. return;
  392. }
  393. /* OPEN THE RASTER FILE TO BE CLIPPED,
  394. AND DO THE CLIPPING */
  395. void cell_clip(DCELL ** buf, DCELL ** null_buf, int row0, int col0, int nrows,
  396. int ncols, int index, int *centernull)
  397. {
  398. CELL *tmp, *tmp1;
  399. FCELL *ftmp;
  400. DCELL *dtmp;
  401. void *rastptr;
  402. char *tmpname, *name, *mapset;
  403. int fr, x;
  404. register int i, j;
  405. double center_row = 0.0, center_col = 0.0;
  406. double dist;
  407. RASTER_MAP_TYPE data_type;
  408. /*
  409. Variables:
  410. IN:
  411. buf = pointer to array containing only the pixels inside the area
  412. that was specified to be clipped, so a smaller array than the
  413. original raster map
  414. null_buf = pointer to array containing 0.0 if pixel in input raster map is
  415. not null and 1.0 if pixel in input raster map is null
  416. row0 = starting row for the area to be clipped out of the raster map
  417. col0 = starting col for the area to be clipped out of the raster map
  418. nrows = total number of rows in the area to be clipped
  419. ncols = total number of cols in the area to be clipped
  420. index = number of the region to be clipped, if there's a region map
  421. centernull = 1 if the center pixel of the clipped area is a null value,
  422. 0 otherwise
  423. INTERNAL:
  424. tmp = pointer to a temporary buffer to store a row of a CELL_TYPE
  425. (integer) raster
  426. ftmp = pointer to a temporary buffer to store a row of an FCELL_TYPE
  427. (floating point) raster
  428. dtmp = pointer to a temporary buffer to store a row of a DCELL_TYPE
  429. (double) raster
  430. tmp1 = pointer to a temporary buffer to store a row of the region map
  431. tmpname = one of the above: tmp, ftmp, dtmp
  432. fr = return value from attempting to open the region map
  433. i, j = indices to rows and cols of the arrays
  434. center_row = row of the center of the circle, if circles used
  435. center_col = column of the center of the circle, if circles used
  436. dist = used to measure distance from a row/column to the center of the
  437. circle, to see if a row/column is within the circle
  438. data_type = the type of raster map: integer, floating point, or double
  439. rastptr = void pointer used to advance through null values in the tmp,
  440. ftmp, or dtmp buffers
  441. */
  442. /* check for input raster map and open it; this
  443. map remains open on finput while all the programs
  444. run, so it is globally available */
  445. name = choice->fn;
  446. if (0 > (finput = Rast_open_old(name, "")))
  447. G_fatal_error(_("Unable to open raster map <%s>"), name);
  448. mapset = G_find_raster2(name, "");
  449. data_type = Rast_map_type(name, mapset);
  450. /* allocate memory to store a row of the
  451. raster map, depending on the type of
  452. input raster map; keep track of the
  453. name of the buffer for each raster type */
  454. switch (data_type) {
  455. case CELL_TYPE:
  456. tmp = Rast_allocate_buf(CELL_TYPE);
  457. tmpname = "tmp";
  458. break;
  459. case FCELL_TYPE:
  460. ftmp = Rast_allocate_buf(FCELL_TYPE);
  461. tmpname = "ftmp";
  462. break;
  463. case DCELL_TYPE:
  464. dtmp = Rast_allocate_buf(DCELL_TYPE);
  465. tmpname = "dtmp";
  466. break;
  467. }
  468. /* zero the buffer used to hold null values */
  469. /* for (i = 0; i < nrows; i++) {
  470. for (j = 0; j < ncols; j++) {
  471. null_buf[i][j]=1.0;
  472. }
  473. }
  474. */
  475. /* for each row of the area to be clipped */
  476. for (i = row0; i < row0 + nrows; i++) {
  477. /* initialize each element of the
  478. row buffer to 0; this row buffer
  479. will hold one row of the clipped
  480. raster map. Then read row i of the
  481. map into tmp buffer */
  482. switch (data_type) {
  483. case CELL_TYPE:
  484. Rast_zero_buf(tmp, data_type);
  485. Rast_get_row(finput, tmp, i, data_type);
  486. break;
  487. case FCELL_TYPE:
  488. Rast_zero_buf(ftmp, data_type);
  489. Rast_get_row(finput, ftmp, i, data_type);
  490. break;
  491. case DCELL_TYPE:
  492. Rast_zero_buf(dtmp, data_type);
  493. Rast_get_row(finput, dtmp, i, data_type);
  494. break;
  495. }
  496. /* set up a void pointer to be used to find null
  497. values in the area to be clipped and advance
  498. the raster pointer to the right starting
  499. column */
  500. switch (data_type) {
  501. case CELL_TYPE:
  502. rastptr = tmp;
  503. for (x = 0; x < col0; x++)
  504. rastptr = G_incr_void_ptr(rastptr, Rast_cell_size(CELL_TYPE));
  505. break;
  506. case FCELL_TYPE:
  507. rastptr = ftmp;
  508. for (x = 0; x < col0; x++)
  509. rastptr = G_incr_void_ptr(rastptr, Rast_cell_size(FCELL_TYPE));
  510. break;
  511. case DCELL_TYPE:
  512. rastptr = dtmp;
  513. for (x = 0; x < col0; x++)
  514. rastptr = G_incr_void_ptr(rastptr, Rast_cell_size(DCELL_TYPE));
  515. break;
  516. }
  517. /* for all the columns one by one */
  518. for (j = col0; j < col0 + ncols; j++) {
  519. /* look for null values in each cell
  520. and set centernull flag to 1 if
  521. center is null */
  522. switch (data_type) {
  523. case CELL_TYPE:
  524. if (Rast_is_null_value(rastptr, CELL_TYPE)) {
  525. *(*(null_buf + i + 1 - row0) + j + 1 - col0) = 1.0;
  526. if (i == row0 + nrows / 2 && j == col0 + ncols / 2)
  527. *centernull = 1;
  528. }
  529. else {
  530. *(*(null_buf + i + 1 - row0) + j + 1 - col0) = 0.0;
  531. }
  532. rastptr = G_incr_void_ptr(rastptr, Rast_cell_size(CELL_TYPE));
  533. break;
  534. case FCELL_TYPE:
  535. if (Rast_is_null_value(rastptr, FCELL_TYPE)) {
  536. *(*(null_buf + i + 1 - row0) + j + 1 - col0) = 1.0;
  537. if (i == row0 + nrows / 2 && j == col0 + ncols / 2)
  538. *centernull = 1;
  539. }
  540. else {
  541. *(*(null_buf + i + 1 - row0) + j + 1 - col0) = 0.0;
  542. }
  543. rastptr = G_incr_void_ptr(rastptr, Rast_cell_size(FCELL_TYPE));
  544. break;
  545. case DCELL_TYPE:
  546. if (Rast_is_null_value(rastptr, DCELL_TYPE)) {
  547. *(*(null_buf + i + 1 - row0) + j + 1 - col0) = 1.0;
  548. if (i == row0 + nrows / 2 && j == col0 + ncols / 2)
  549. *centernull = 1;
  550. }
  551. else {
  552. *(*(null_buf + i + 1 - row0) + j + 1 - col0) = 0.0;
  553. }
  554. rastptr = G_incr_void_ptr(rastptr, Rast_cell_size(CELL_TYPE));
  555. break;
  556. }
  557. /* copy the contents of the correct tmp
  558. into the appropriate cell in the buf
  559. and the corresponding null values into
  560. the appropriate cell in null_buf */
  561. switch (data_type) {
  562. case CELL_TYPE:
  563. *(*(buf + i + 1 - row0) + j + 1 - col0) = *(tmp + j);
  564. break;
  565. case FCELL_TYPE:
  566. *(*(buf + i + 1 - row0) + j + 1 - col0) = *(ftmp + j);
  567. break;
  568. case DCELL_TYPE:
  569. *(*(buf + i + 1 - row0) + j + 1 - col0) = *(dtmp + j);
  570. break;
  571. }
  572. }
  573. }
  574. switch (data_type) {
  575. case CELL_TYPE:
  576. G_free(tmp);
  577. break;
  578. case FCELL_TYPE:
  579. G_free(ftmp);
  580. break;
  581. case DCELL_TYPE:
  582. G_free(dtmp);
  583. break;
  584. }
  585. return;
  586. }
  587. /* DRIVER TO LOOK FOR NEW PATCHES, CALL
  588. THE TRACING ROUTINE, AND ADD NEW PATCHES
  589. TO THE PATCH LIST */
  590. void trace(int nrows, int ncols, DCELL **buf, DCELL **null_buf, CELL **pat)
  591. {
  592. double class = 0.0;
  593. register int i, j;
  594. PATCH *tmp, *find_any, *list_head;
  595. /*
  596. Variables:
  597. EXTERN:
  598. IN:
  599. nrows = total number of rows in the area where tracing will occur
  600. ncols = total number of cols in the area where tracing will occur
  601. buf = pointer to array containing only the pixels inside the area
  602. that was clipped and within which tracing will now occur, so
  603. a smaller array than the original raster map
  604. null_buf = pointer to array containing 0.0 if pixel in input raster map is
  605. not null and 1.0 if pixel in input raster map is null
  606. pat = pointer to array containing the map of patch numbers; this map
  607. can only be integer
  608. INTERNAL:
  609. class = the attribute of each pixel
  610. i, j = counts the row and column as the program goes through the area
  611. tmp = pointer to a member of the PATCH list data structure, used to
  612. advance through the patch list
  613. find_any = pointer to a member of the patch list to hold the results after
  614. routine get_bd is called to trace the boundary of the patch and
  615. save the patch information in the PATCH data structure
  616. list_head = pointer to the first member of the patch list
  617. */
  618. /* go thru buf, which contains the entries
  619. within the clipped window, column by
  620. column and row by row; Note that now the
  621. rows and cols are counted from 1 to nrows
  622. and 1 to ncols, not from 0 to < nrows and
  623. 0 to < ncols */
  624. i = 0;
  625. while (i++ < nrows) { /*1 */
  626. j = 0;
  627. while (j++ < ncols) {
  628. /* if this pt contains a positive or negative
  629. raster value or a zero, and null value is
  630. 0.0, it may be the start of an untraced
  631. patch */
  632. if ((*(*(buf + i) + j) || *(*(buf + i) + j) == 0.0) && *(*(null_buf + i) + j) == 0.0) { /*3 */
  633. class = *(*(buf + i) + j);
  634. /* trace the patch from the current pt */
  635. list_head = patch_list;
  636. if ((find_any = get_bd(i, j, nrows, ncols, class, buf, null_buf, list_head, pat))) { /*4 */
  637. /* if the first patch, make tmp point to
  638. the patch list and add the first patch
  639. to the list */
  640. if (total_patches == 0) {
  641. patch_list = find_any;
  642. tmp = patch_list;
  643. }
  644. /* add the next patch to the patch list */
  645. else {
  646. tmp->next = find_any;
  647. tmp = tmp->next;
  648. }
  649. /* increment the count of total patches */
  650. fprintf(stderr, "Tracing patch %7d\r", total_patches + 1);
  651. total_patches++;
  652. } /*4 */
  653. /* if i and j are now at or outside the
  654. limits of the window, then quit */
  655. if (i >= nrows && j >= ncols) {
  656. return;
  657. }
  658. } /*3 */
  659. /* if this pt is the boundary point of an
  660. already traced patch or is outside the
  661. window, do not start tracing; skip to
  662. next pt */
  663. else { /*5 */
  664. /* if i and j are now at or outside the
  665. limits of the window, then quit */
  666. if (i >= nrows && j >= ncols)
  667. return;
  668. } /*5 */
  669. } /*2 */
  670. }
  671. return; /*1 */
  672. }
  673. /* TRACE THE BOUNDARY OF A PATCH AND
  674. SAVE THE PATCH CHARACTERISTICS IN
  675. THE PATCH STRUCTURE */
  676. PATCH *get_bd(int row0, int col0, int nrows, int ncols, double class,
  677. DCELL ** buf, DCELL ** null_buf, PATCH * p_list, CELL ** pat)
  678. {
  679. int i = row0, j = col0, pts = 0, di = 0, dj = -1,
  680. not_done, k, m, tmp, lng = 0, roww = 0, rowe = 0,
  681. coln = 0, cols = 0, row1, col1, di2, dj2, p, q, area, per, nozero;
  682. int ***twist2, trows, tcols, n, e, a, b, twistnum = 0;
  683. float ***twistP, sumT, omega;
  684. PATCH *patch;
  685. CELL **patchmap;
  686. PT *ptrfirst, *ptrthis, *ptrnew, *ptrfree;
  687. /*
  688. Variables:
  689. IN:
  690. row0 = row for the first pixel in the patch
  691. col0 = column for the first pixel in the patch
  692. nrows = number of rows in the clipped area
  693. ncols = number of columns in the clipped area
  694. class = attribute of the patch being traced
  695. buf = pointer to array containing only the pixels inside the area
  696. that was clipped
  697. null_buf = pointer to array containing 0.0 if pixel in input raster map is
  698. not null and 1.0 if pixel in input raster map is null
  699. p_list = pointer to the patch list
  700. pat = pointer to array containing the map of patch numbers; this map
  701. can only be integer
  702. INTERNAL
  703. i, j = counts the row and column as tracing occurs
  704. pts = counts the number of points as tracing proceeds
  705. di, dj = indicates moves of 1 pixel in the row or column direction, used
  706. to examine adjoining 4- or 8-neighboring pixels when tracing
  707. not_done = flag to indicate when the patch has not been fully traced yet
  708. k =
  709. m =
  710. tmp = integer to hold intermediate results in calculation of long axis
  711. of patch
  712. lng = integer to hold the calculated long axis of the patch
  713. roww = integer to hold the westernmost point in each row of the patch
  714. rowe = integer to hold the easternmost point in each row of the patch
  715. coln = integer to hold the northernmost point in each row of the patch
  716. cols = integer to hold the southernmost point in each row of the patch
  717. row1 = integer to hold the starting row for tracing internal boundaries
  718. col1 = integer to hold the starting column for tracing internal boundaries
  719. di2, dj2 = indicates moves of 1 pixel in the row or column direction, used
  720. to examine adjoining 4- or 8-neighboring pixels when tracing
  721. internal boundaries of a patch
  722. p, q = row and column indices for tracing patch internal boundaries
  723. area = patch area
  724. per = patch perimeter
  725. nozero =
  726. twist2 = 2-dimensional array to hold preliminary countes needed to calculate
  727. the twist number and omega index
  728. trows = number of rows in the bounding box for the patch
  729. tcols = number of columns in the bounding box for the patch
  730. n, e = northing (in rows) and easting (in columns) for the patch
  731. a, b = indexes particular pixels used in calculating twist number in certain
  732. cases
  733. twistnum = twist number
  734. twistP = 2-dimensional array to hold P values used in the calculation of twist
  735. number
  736. sumT = the floating point version of twist number
  737. omega = omega index
  738. patch = pointer to a member of the patch list
  739. patchmap = 2-dimensional array holding 1's for pixels inside the patch and
  740. zero otherwise
  741. ptrfirst = pointer to the first element of the linked list of patches
  742. ptrthis = pointer to the current element of the linked list of patches
  743. ptrnew = pointer to a new element of the linked list of patches
  744. ptrfree =
  745. */
  746. /* allocate memory for 1 patch to be
  747. saved in the patch data structure */
  748. patch = (PATCH *) G_calloc(1, sizeof(PATCH));
  749. /* allocate memory for patchmap, which
  750. will hold the patch boundaries found in
  751. the buf array */
  752. patchmap = (CELL **) G_calloc(nrows + 3, sizeof(CELL *));
  753. for (m = 0; m < nrows + 3; m++)
  754. patchmap[m] = (CELL *) Rast_allocate_buf(CELL_TYPE);
  755. /* if this is the first patch to be traced,
  756. then set the next patch on the patch list
  757. to NULL */
  758. if (total_patches == 0)
  759. patch->next = (PATCH *) NULL;
  760. /* this loop goes until the patch has been
  761. traced */
  762. for (;;) { /*1 */
  763. /* STEP 1: RECORD ATTRIBUTE AND PATCH NUMBER,
  764. THEN TRACE THE PTS IN THE BOUNDARY,
  765. RECORDING THE ROW AND COL OF EACH PT, AND
  766. FINDING THE PATCH BOUNDING BOX */
  767. /* initialize variables */
  768. not_done = 1;
  769. patch->s = 0;
  770. patch->e = 0;
  771. patch->w = (int)BIG;
  772. patch->n = (int)BIG;
  773. /* while tracing is not done */
  774. while (not_done) { /*2 */
  775. /* if this is the first pt in the patch,
  776. fill the PATCH structure with the
  777. attribute and number of the patch,
  778. and set the first pt to NULL */
  779. if (pts == 0) {
  780. patch->att = class;
  781. patch->num = total_patches + 1;
  782. ptrfirst = (PT *) NULL;
  783. }
  784. /* if this pt has a non-null value and
  785. it hasn't been traced.
  786. (1) put a 1 in patchmap at the location.
  787. This will keep track of all the pixels
  788. that get traced in this one patch.
  789. (2) make the null_buf value a 1.0. This
  790. will keep track of all the pixels that
  791. get traced or are otherwise null in all
  792. the patches in the buffer. Once they
  793. are null, they don't get traced again.
  794. (3) save the row & col in PATCH structure,
  795. (4) see if the pt expands the current
  796. bounding box
  797. (5) increment the pts count */
  798. /*printf("num=%d i=%d j=%d buf=%f patchmap=%d null=%f START GET_BD\n",
  799. patch->num,i,j,*(*(buf + i) + j),*(*(patchmap + i) + j), *(*(null_buf + i) +
  800. j));
  801. */
  802. if ((*(*(buf + i) + j) ||
  803. *(*(buf + i) + j) == 0.0) &&
  804. *(*(patchmap + i) + j) == 0 &&
  805. *(*(null_buf + i) + j) == 0.0) {
  806. *(*(patchmap + i) + j) = 1;
  807. *(*(null_buf + i) + j) = 1.0;
  808. ptrnew = (PT *) G_calloc(1, sizeof(PT));
  809. if (ptrfirst == (PT *) NULL) {
  810. ptrfirst = ptrthis = ptrnew;
  811. }
  812. else {
  813. ptrthis = ptrfirst;
  814. while (ptrthis->next != (PT *) NULL)
  815. ptrthis = ptrthis->next;
  816. ptrthis->next = ptrnew;
  817. ptrthis = ptrnew;
  818. }
  819. ptrthis->row = i;
  820. ptrthis->col = j;
  821. if (i > patch->s)
  822. patch->s = i;
  823. if (i < patch->n)
  824. patch->n = i;
  825. if (j > patch->e)
  826. patch->e = j;
  827. if (j < patch->w)
  828. patch->w = j;
  829. pts++;
  830. }
  831. /*printf("3. i=%d j=%d s=%d n=%d w=%d e=%d\n",i,j, patch->s, patch->n,
  832. patch->w,patch->e); */
  833. /* if there is a neighboring pixel, with the
  834. same class, moving clockwise around the
  835. patch, then reset i and j to this
  836. location, then reset di and dj */
  837. if (yes_nb(&di, &dj, buf, class, i, j, nrows, ncols)) {
  838. i = i + di;
  839. j = j + dj;
  840. di = -di;
  841. dj = -dj;
  842. clockwise(&di, &dj);
  843. /*printf("num=%d i=%d j=%d buf=%f patchmap=%d null=%d row0=%d col0=%d \
  844. AFTER YES_NB\n",
  845. patch->num,i,j, *(*(buf + i) + j), *(*(patchmap + i) + j),
  846. *(*(null_buf + i) + j), row0, col0);
  847. */
  848. /* if tracing has returned to the starting
  849. pt, then stop; in a special case with
  850. diagonal tracing, don't stop if there is
  851. a traceable pixel below and to the left
  852. and if there is a below and to the left */
  853. if (i == row0 && j == col0) {
  854. not_done = 0;
  855. if (choice->trace &&
  856. (i < nrows) && (j > 1) &&
  857. *(*(buf + i + 1) + j - 1) == class &&
  858. (*(*(patchmap + i + 1) + j - 1) == 0) &&
  859. (*(*(null_buf + i + 1) + j - 1) == 0.0)) {
  860. /*printf("IN NOT DONE i=%d j=%d i=%d j=%d buf=%f patchmap=%d null_buf=%f\n",
  861. i,j,i+1,j-1,*(*(buf + i + 1) + j - 1),*(*(patchmap + i + 1) + j - 1),
  862. *(*(null_buf + i + 1) + j - 1)); */
  863. not_done = 1;
  864. }
  865. }
  866. }
  867. /* if there is no neighboring pixel with the
  868. same class, then stop tracing */
  869. else
  870. not_done = 0;
  871. } /*2 */
  872. /* STEP 2: CLEAN AND FILL THE PATCH WITHIN
  873. ITS BOUNDARIES. THE MAP IS CLEANED AND
  874. FILLED INTO "PATCHMAP" WHICH THEN CONTAINS
  875. THE FOLLOWING VALUES:
  876. 1 = BOUNDARY PT
  877. -999 = INTERIOR (NON BOUNDARY) PT */
  878. for (i = patch->n; i < patch->s + 1; i++) { /*3 */
  879. /* find the westernmost and easternmost boundary
  880. points in row i */
  881. roww = patch->w;
  882. rowe = patch->e;
  883. while (*(*(patchmap + i) + roww) == 0 && roww < patch->e)
  884. roww++;
  885. while (*(*(patchmap + i) + rowe) == 0 && rowe > patch->w)
  886. rowe--;
  887. /* if the westernmost and easternmost boundary
  888. pts in row i are not the same or are not
  889. next to each other, then we need to scan
  890. across row i */
  891. if (roww != rowe && roww + 1 != rowe) { /*4 */
  892. for (j = roww; j < rowe; j++) { /*5 */
  893. /* if this pixel is one of the traced boundary
  894. or interior pts and the next pixel in the row
  895. is not one of these or has not been traced, */
  896. if (*(*(patchmap + i) + j) != 0 && *(*(patchmap + i) + j + 1) == 0) { /*6 */
  897. /* if the next pixel has the same class, then
  898. give that pixel a -999 in patchmap to signify
  899. that it is part of the patch, and make null_buf
  900. a 1.0 to signify that this next pixel has been
  901. traced */
  902. if (*(*(buf + i) + j + 1) == class) {
  903. *(*(patchmap + i) + j + 1) = -999;
  904. *(*(null_buf + i) + j + 1) = 1.0;
  905. }
  906. /* but if the next pixel doesn't have the same
  907. class, then the present pixel marks the edge
  908. of a potential interior boundary for the patch.
  909. Trace this boundary only if it has not already
  910. been traced */
  911. else if (*(*(buf + i) + j + 1) != class && (*(*(patchmap + i) + j) != 1 || *(*(patchmap + i) + j + 1) == 0)) { /*7 */
  912. not_done = 1;
  913. row1 = p = i;
  914. col1 = q = j;
  915. di2 = 0;
  916. dj2 = 1;
  917. while (not_done) { /*8 */
  918. if (*(*(patchmap + p) + q) == -999)
  919. *(*(patchmap + p) + q) = 4;
  920. if (*(*(patchmap + p) + q) == 4) {
  921. ptrnew = (PT *) G_calloc(1, sizeof(PT));
  922. ptrthis = ptrfirst;
  923. while (ptrthis->next != (PT *) NULL)
  924. ptrthis = ptrthis->next;
  925. ptrthis->next = ptrnew;
  926. ptrthis = ptrnew;
  927. ptrthis->row = p;
  928. ptrthis->col = q;
  929. *(*(patchmap + p) + q) = 1;
  930. *(*(null_buf + p) + q) = 1.0;
  931. pts++;
  932. }
  933. if (yes_nb(&di2, &dj2, buf, class, p, q,
  934. nrows, ncols)) {
  935. p = p + di2;
  936. q = q + dj2;
  937. if (*(*(patchmap + p) + q) != 1) {
  938. *(*(patchmap + p) + q) = 4;
  939. *(*(null_buf + p) + q) = 1.0;
  940. }
  941. di2 = -di2;
  942. dj2 = -dj2;
  943. clockwise(&di2, &dj2);
  944. if (p == row1 && q == col1) {
  945. not_done = 0;
  946. }
  947. }
  948. else
  949. not_done = 0;
  950. } /*8 */
  951. } /*7 */
  952. } /*6 */
  953. } /*5 */
  954. } /*4 */
  955. } /*3 */
  956. /* STEP 3: GO THROUGH THE RESULTING PATCHMAP AND DETERMINE
  957. THE PATCH SIZE, AMOUNT OF PERIMETER */
  958. area = 0;
  959. per = 0;
  960. for (i = patch->n; i < patch->s + 1; i++) {
  961. for (j = patch->w; j < patch->e + 1; j++) {
  962. if (*(*(patchmap + i) + j) || *(*(patchmap + i) + j) == -999) {
  963. area++;
  964. if (choice->perim2 == 0) {
  965. if (j == 1 || j == ncols)
  966. per++;
  967. }
  968. if (j < ncols && *(*(patchmap + i) + j + 1) == 0)
  969. per++;
  970. if (j > 1 && *(*(patchmap + i) + j - 1) == 0)
  971. per++;
  972. /* if a num map was requested with the -n flag,
  973. then copy the patch numbers into pat array */
  974. if (choice->patchmap)
  975. *(*(pat + i) + j) = patch->num;
  976. }
  977. }
  978. }
  979. for (j = patch->w; j < patch->e + 1; j++) {
  980. for (i = patch->n; i < patch->s + 1; i++) {
  981. if (*(*(patchmap + i) + j) || *(*(patchmap + i) + j) == -999) {
  982. if (choice->perim2 == 0) {
  983. if (i == 1 || i == nrows)
  984. per++;
  985. }
  986. if (i < nrows && *(*(patchmap + i + 1) + j) == 0)
  987. per++;
  988. if (i > 1 && *(*(patchmap + i - 1) + j) == 0)
  989. per++;
  990. }
  991. }
  992. }
  993. patch->area = area;
  994. patch->perim = per;
  995. /* STEP 4: GO THROUGH THE RESULTING LIST OF PTS,
  996. RECORD THE ROW AND COL IN THE PATCH
  997. STRUCTURE, AND FIND THE LONG AXIS AND
  998. CENTER OF THE PATCH */
  999. patch->npts = pts;
  1000. /* allocate enough memory to store the list of
  1001. pts in the PATCH structure */
  1002. patch->col = (int *)G_calloc(pts, sizeof(int));
  1003. patch->row = (int *)G_calloc(pts, sizeof(int));
  1004. /* go through the list of pts */
  1005. i = 0;
  1006. ptrthis = ptrfirst;
  1007. while (ptrthis) {
  1008. ptrfree = ptrthis;
  1009. /* save the pt locat. in the PATCH structure */
  1010. *(patch->row + i) = ptrthis->row;
  1011. *(patch->col + i) = ptrthis->col;
  1012. /* long-axis step 1: find the largest
  1013. sum of squares between patch boundary
  1014. pts if the Related Circumscribing Circle
  1015. shape index is requested */
  1016. if (pts == 1) {
  1017. lng = 2;
  1018. }
  1019. else {
  1020. for (j = 0; j < i + 1; j++) {
  1021. if ((tmp =
  1022. (abs(*(patch->row + j) - *(patch->row + i)) +
  1023. 1) * (abs(*(patch->row + j) - *(patch->row + i)) +
  1024. 1) + (abs(*(patch->col + j) -
  1025. *(patch->col + i)) +
  1026. 1) * (abs(*(patch->col + j) -
  1027. *(patch->col + i)) + 1)) >
  1028. lng)
  1029. lng = tmp;
  1030. }
  1031. }
  1032. /* patch center step 1: sum up the boundary
  1033. coordinates */
  1034. if (i < pts) {
  1035. patch->c_row += *(patch->row + i);
  1036. patch->c_col += *(patch->col + i);
  1037. }
  1038. ptrthis = ptrthis->next;
  1039. G_free(ptrfree);
  1040. i++;
  1041. }
  1042. /* patch long axis and center step 2: complete
  1043. the calculations */
  1044. patch->long_axis = sqrt((double)(lng));
  1045. patch->c_col = (int)(patch->c_col / pts + 0.5);
  1046. patch->c_row = (int)(patch->c_row / pts + 0.5);
  1047. /* STEP 5: GO THROUGH THE PATCHMAP AND CALCULATE TWIST & OMEGA */
  1048. if (1) {
  1049. /* dynamically allocate storage for the arrays that will
  1050. hold the twist tallies and P values */
  1051. trows = patch->s - patch->n + 3;
  1052. tcols = patch->e - patch->w + 3;
  1053. twist2 = (int ***)G_calloc(trows + 3, sizeof(int **));
  1054. for (i = 0; i < trows + 3; i++) {
  1055. twist2[i] = (int **)G_calloc(tcols + 3, sizeof(int *));
  1056. for (j = 0; j < tcols + 3; j++)
  1057. twist2[i][j] = (int *)G_calloc(7, sizeof(int));
  1058. }
  1059. twistP = (float ***)G_calloc(trows + 3, sizeof(float **));
  1060. for (i = 0; i < trows + 3; i++) {
  1061. twistP[i] = (float **)G_calloc(tcols + 3, sizeof(float *));
  1062. for (j = 0; j < tcols + 3; j++)
  1063. twistP[i][j] = (float *)G_calloc(7, sizeof(float));
  1064. }
  1065. /* zero the twist2 and twistP matrices */
  1066. for (i = 0; i < trows + 3; i++) {
  1067. for (j = 0; j < tcols + 3; j++) {
  1068. for (k = 0; k < 5; k++) {
  1069. twist2[i][j][k] = 0;
  1070. twistP[i][j][k] = 0.0;
  1071. }
  1072. }
  1073. }
  1074. /* fill the twist2 matrix with counts; do this for
  1075. each pixel in the patch, identified by having a
  1076. value of 1 or -999 */
  1077. for (i = patch->n; i < patch->s + 1; i++) {
  1078. for (j = patch->w; j < patch->e + 1; j++) {
  1079. n = i - patch->n + 1;
  1080. e = j - patch->w + 1;
  1081. if (*(*(patchmap + i) + j) > 0 ||
  1082. *(*(patchmap + i) + j) == -999) {
  1083. if (*(*(patchmap + i) + j - 1) > 0 ||
  1084. *(*(patchmap + i) + j - 1) == -999)
  1085. twist2[n][e][0]++;
  1086. if (*(*(patchmap + i - 1) + j - 1) > 0 ||
  1087. *(*(patchmap + i - 1) + j - 1) == -999)
  1088. twist2[n][e][0]++;
  1089. if (*(*(patchmap + i - 1) + j) > 0 ||
  1090. *(*(patchmap + i - 1) + j) == -999)
  1091. twist2[n][e][0]++;
  1092. if (*(*(patchmap + i - 1) + j) > 0 ||
  1093. *(*(patchmap + i - 1) + j) == -999)
  1094. twist2[n][e][1]++;
  1095. if (*(*(patchmap + i - 1) + j + 1) > 0 ||
  1096. *(*(patchmap + i - 1) + j + 1) == -999)
  1097. twist2[n][e][1]++;
  1098. if (*(*(patchmap + i) + j + 1) > 0 ||
  1099. *(*(patchmap + i) + j + 1) == -999)
  1100. twist2[n][e][1]++;
  1101. if (*(*(patchmap + i) + j + 1) > 0 ||
  1102. *(*(patchmap + i) + j + 1) == -999)
  1103. twist2[n][e][2]++;
  1104. if (*(*(patchmap + i + 1) + j + 1) > 0 ||
  1105. *(*(patchmap + i + 1) + j + 1) == -999)
  1106. twist2[n][e][2]++;
  1107. if (*(*(patchmap + i + 1) + j) > 0 ||
  1108. *(*(patchmap + i + 1) + j) == -999)
  1109. twist2[n][e][2]++;
  1110. if (*(*(patchmap + i + 1) + j) > 0 ||
  1111. *(*(patchmap + i + 1) + j) == -999)
  1112. twist2[n][e][3]++;
  1113. if (*(*(patchmap + i + 1) + j - 1) > 0 ||
  1114. *(*(patchmap + i + 1) + j - 1) == -999)
  1115. twist2[n][e][3]++;
  1116. if (*(*(patchmap + i) + j - 1) > 0 ||
  1117. *(*(patchmap + i) + j - 1) == -999)
  1118. twist2[n][e][3]++;
  1119. /* calculate the P values based on the tallies */
  1120. for (k = 0; k < 4; k++) {
  1121. if (*(*(patchmap + i) + j) > 0 ||
  1122. *(*(patchmap + i) + j) == -999) {
  1123. if (twist2[n][e][k] - 1 < 0)
  1124. twistP[n][e][k] = 1.0;
  1125. else if (twist2[n][e][k] - 1 == 0) {
  1126. if (k - 1 > 0)
  1127. a = i + 1;
  1128. else
  1129. a = i - 1;
  1130. if (k == 1 || k == 2)
  1131. b = j + 1;
  1132. else
  1133. b = j - 1;
  1134. if (*(*(patchmap + a) + b) > 0 ||
  1135. *(*(patchmap + a) + b) == -999)
  1136. twistP[n][e][k] = 1.0;
  1137. else
  1138. twistP[n][e][k] = 0.0;
  1139. }
  1140. else if (twist2[n][e][k] - 1 > 0) {
  1141. if (twist2[n][e][k] == 3)
  1142. twistP[n][e][k] = 0.0;
  1143. else if (twist2[n][e][k] == 2)
  1144. twistP[n][e][k] = .33333;
  1145. }
  1146. }
  1147. }
  1148. }
  1149. }
  1150. }
  1151. /* sum up the P values to calculate the twist number */
  1152. sumT = 0.0;
  1153. for (n = 0; n < trows; n++) {
  1154. for (e = 0; e < tcols; e++) {
  1155. for (k = 0; k < 4; k++)
  1156. sumT = sumT + twistP[n][e][k];
  1157. }
  1158. }
  1159. patch->twist = (int)(sumT + 0.5);
  1160. /* calculate the omega index for 3 cases, depending upon
  1161. whether 8-neighbor or 4-neighbor tracing was chosen */
  1162. if (choice->trace) {
  1163. if (patch->area > 1.0)
  1164. patch->omega = (4.0 * patch->area - (float)patch->twist) /
  1165. (4.0 * patch->area - 4.0);
  1166. else
  1167. patch->omega = 0.0;
  1168. }
  1169. else {
  1170. if ((((int)patch->area % 4) - 1) == 0) {
  1171. if (patch->area > 1.0)
  1172. patch->omega =
  1173. (2.0 * patch->area + 2.0 -
  1174. (float)patch->twist) / (2.0 * patch->area - 2.0);
  1175. else
  1176. patch->omega = 0.0;
  1177. }
  1178. else if (patch->area > 2.0)
  1179. patch->omega = (2.0 * patch->area - (float)patch->twist) /
  1180. (2.0 * patch->area - 4.0);
  1181. else
  1182. patch->omega = 0.0;
  1183. }
  1184. /*printf("twistnum = %4d omega=%6.4f area=%7.0f\n", patch->twist,
  1185. patch->omega,patch->area);
  1186. */
  1187. /* free memory allocated for holding twist tallies and
  1188. P values */
  1189. for (i = 0; i < trows + 3; i++) {
  1190. for (j = 0; j < tcols + 3; j++)
  1191. G_free(twistP[i][j]);
  1192. G_free(twistP[i]);
  1193. }
  1194. G_free(twistP);
  1195. for (i = 0; i < trows + 3; i++) {
  1196. for (j = 0; j < tcols + 3; j++)
  1197. G_free(twist2[i][j]);
  1198. G_free(twist2[i]);
  1199. }
  1200. G_free(twist2);
  1201. }
  1202. /* STEP 6: MAKE NEXT PATCH NULL, FREE MEMORY,
  1203. AND RETURN THE PATCH STRUCTURE */
  1204. patch->next = (PATCH *) NULL;
  1205. /* free the memory allocated for patchmap */
  1206. for (i = 0; i < nrows + 3; i++)
  1207. G_free(patchmap[i]);
  1208. G_free(patchmap);
  1209. /* send the patch info back to trace */
  1210. return (patch);
  1211. } /*1 */
  1212. }
  1213. /* SEARCH THE 8 NEIGHBORS OF A PIXEL IN
  1214. THE BUFFER IN A CLOCKWISE DIRECTION
  1215. LOOKING FOR A PIXEL WITH THE SAME
  1216. CLASS AND RETURN A 1 AND DI, DJ FOR
  1217. THE FIRST PIXEL FOUND; OTHERWISE RETURN
  1218. A ZERO */
  1219. int yes_nb(int *di, int *dj, DCELL ** buf, double class, int i, int j,
  1220. int nrows, int ncols)
  1221. {
  1222. /* di=0 to start; di is the value to be added to i to get to the
  1223. pixel with the same value
  1224. dj=-1 to start; dj is the value to be added to j to get to the
  1225. pixel with the same value
  1226. class = the attribute of the center pixel
  1227. */
  1228. register int k;
  1229. /*printf("1i=%d di=%d j=%d dj=%d nrows=%d
  1230. ncols=%d\n",i,*di,j,*dj,nrows,ncols); */
  1231. /* if tracing is to include crossing to
  1232. diagonal pixels */
  1233. if (choice->trace) { /*1 */
  1234. /* search through the 8 neighbor pixels */
  1235. for (k = 0; k < 8; k++) {
  1236. /* if the neighbor pixel has the same
  1237. attribute as that of the current pixel,
  1238. then it may be part of the patch.
  1239. Confine the search to only pixels
  1240. inside the buffer to avoid a crash! */
  1241. if ((i + *di > 0) && (j + *dj > 0) &&
  1242. (i + *di <= nrows) && (j + *dj <= ncols)) {
  1243. if (class == *(*(buf + i + *di) + j + *dj))
  1244. return 1;
  1245. }
  1246. clockwise(di, dj);
  1247. }
  1248. /* if no neighbor with the same class is found,
  1249. then we are done tracing the patch */
  1250. return 0;
  1251. } /*1 */
  1252. /* if tracing is not to include crossing to
  1253. diagonal pixels */
  1254. else {
  1255. /* search through the 8 neighbor pixels */
  1256. for (k = 0; k < 8; k++) {
  1257. /* if the neighbor pixel has the same
  1258. attribute as that of the current pixel,
  1259. then maybe it is part of the same patch */
  1260. if ((i + *di > 0) && (j + *dj > 0) &&
  1261. (i + *di <= nrows) && (j + *dj <= ncols)) {
  1262. if (class == *(*(buf + i + *di) + j + *dj)) {
  1263. /* if the neighbor pixel is directly above,
  1264. below, to the right or left of the current
  1265. pixel then tracing can continue */
  1266. if (*di == 0 || *dj == 0)
  1267. return 1;
  1268. /* next check the diagonal neighbors
  1269. that have a bishops pattern and if
  1270. they have an adjacent pixel with the same
  1271. class then continue tracing, as they are
  1272. not isolated diagonal pixels */
  1273. /* lower left bishops pattern */
  1274. if (*di == 1 && *dj == -1)
  1275. if ((class == *(*(buf + i + *di) + j)) ||
  1276. (class == *(*(buf + i) + j + *dj)))
  1277. return 1;
  1278. /* upper left bishops pattern */
  1279. if (*di == -1 && *dj == -1)
  1280. if ((class == *(*(buf + i + *di) + j)) ||
  1281. (class == *(*(buf + i) + j + *dj)))
  1282. return 1;
  1283. /* upper right bishops pattern */
  1284. if (*di == -1 && *dj == 1)
  1285. if ((class == *(*(buf + i + *di) + j)) ||
  1286. (class == *(*(buf + i) + j + *dj)))
  1287. return 1;
  1288. /* lower right bishops pattern */
  1289. if (*di == 1 && *dj == 1)
  1290. if ((class == *(*(buf + i + *di) + j)) ||
  1291. (class == *(*(buf + i) + j + *dj)))
  1292. return 1;
  1293. }
  1294. }
  1295. /* if the neighbor pixel has a different
  1296. class or it is not in the
  1297. same row or col and is an isolated
  1298. bishops pattern pixel, then don't
  1299. trace it, but go to the next one
  1300. of the 8 neighbors */
  1301. clockwise(di, dj);
  1302. }
  1303. /* if all the neighbors are isolated
  1304. bishops pattern pixels or no
  1305. neighbor with the same class is found
  1306. then we are done tracing the patch */
  1307. return (0);
  1308. }
  1309. }
  1310. /* CIRCLE CLOCKWISE AROUND THE CURRENT PT */
  1311. void clockwise(int *i, int *j)
  1312. {
  1313. if (*i != 0 && *j != -*i)
  1314. *j -= *i;
  1315. else
  1316. *i += *j;
  1317. return;
  1318. }