12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829 |
- /*
- ************************************************************
- * MODULE: r.le.patch/trace.c *
- * Version 5.0 Nov. 1, 2001 *
- * *
- * AUTHOR: W.L. Baker, University of Wyoming *
- * BAKERWL@UWYO.EDU *
- * *
- * PURPOSE: To analyze attributes of patches in a landscape *
- * trace.c traces the patch boundary, obtains basic *
- * patch attribute data, and saves this in the *
- * patch structure *
- * *
- * COPYRIGHT: (C) 2001 by W.L. Baker *
- * *
- * This program is free software under the GNU General *
- * Public License(>=v2). Read the file COPYING that comes *
- * with GRASS for details *
- * *
- ************************************************************/
- #include <grass/gis.h>
- #include <grass/config.h>
- #include "patch.h"
- extern struct CHOICE *choice;
- extern struct REGLIST *reglist;
- extern int finput;
- int total_patches = 0;
- PATCH *patch_list = NULL;
- /* DRIVER FOR CELL CLIPPING, TRACING,
- AND CALCULATIONS */
- void cell_clip_drv(int col0, int row0, int ncols, int nrows, double **value,
- int index, float radius)
- {
- CELL **pat, *pat_buf, *cor_cell_buf;
- FCELL *cor_fcell_buf;
- DCELL **buf, **cor, *cor_dcell_buf;
- DCELL **null_buf;
- int i, j, fd, fe, p, infd, centernull = 0, empty = 1;
- int hist_ok, colr_ok, cats_ok, range_ok;
- char *mapset, *name;
- PATCH *list_head;
- struct History hist;
- struct Categories cats;
- struct Categories newcats;
- struct Cell_stats stats;
- struct Colors colr;
- struct Range range;
- struct FPRange fprange;
- struct Quant quant;
- RASTER_MAP_TYPE data_type;
- /*
- Variables:
- EXTERN:
- finput = the input raster map
- patch_list = the patch list
- IN:
- col0 = starting column for area to be clipped
- row0 = starting row for area to be clipped
- ncols = number of columns in area to be clipped
- nrows = number of rows in area to be clipped
- value = array containing a full row of the results of the moving
- window for all the chosen measures if a moving window map,
- otherwise 0
- index = number of the region to be clipped, if there's a region map,
- number of the column if a moving window
- INTERNAL:
- pat = pointer to array containing the map of patch numbers; this map
- can only be integer
- pat_buf = row buffer to temporarily hold results for patch number map
- buf = pointer to array containing the clipped area, a smaller area
- than the original raster map to be read from finput; this map
- can be integer, floating point, or double, but is stored as a
- double throughout the program
- cor = pointer to array containing the map of interior area; this map
- can be integer, floating point, or double, but is stored as a
- double throughout the program
- cor_cell_buf = pointer to row buffer to temporarily hold results for core map if
- input map is integer (CELL_TYPE)
- cor_fcell_buf = pointer to row buffer to temporarily hold results for core map if
- input map is float (FCELL_TYPE)
- cor_dcell_buf = pointer to row buffer to temporarily hold results for core map if
- input map is double (DCELL_TYPE)
- null_buf = pointer to array containing 0.0 if pixel in input raster map is
- not null and 1.0 if pixel in input raster map is null
- infd = pointer to file with map of patches
- i, j = counts the row and column when going through arrays
- p = counts the number of measures in
- fd = pointer to file to hold patch number map
- fe = pointer to file to hold patch interior map
- mapset = the name of the mapset for the raster map being analyzed
- name = the name of the raster map being analyzed
- list_head = point to the patch list
- */
- total_patches = 0;
- name = choice->fn;
- mapset = G_mapset();
- data_type = Rast_map_type(name, mapset);
- /* dynamically allocate storage for the
- buffer that will hold the contents of
- the clipped area */
- buf = (DCELL **) G_calloc(nrows + 3, sizeof(DCELL *));
- for (i = 0; i < nrows + 3; i++) {
- buf[i] = (DCELL *) Rast_allocate_buf(DCELL_TYPE);
- }
- /* dynamically allocate storage for the
- buffer that will hold the null values for
- the clipped area */
- null_buf = (DCELL **) G_calloc(nrows + 3, sizeof(DCELL *));
- for (i = 0; i < nrows + 3; i++)
- null_buf[i] = (DCELL *) Rast_allocate_buf(DCELL_TYPE);
- /* if a map of patch cores was requested,
- dynamically allocate storage for the
- buffer that will temporarily hold the map,
- then initialize the buffer with null values */
- if (choice->coremap) {
- cor = (DCELL **) G_calloc(nrows + 3, sizeof(DCELL *));
- for (i = 0; i < nrows + 3; i++) {
- cor[i] = (DCELL *) Rast_allocate_buf(DCELL_TYPE);
- }
- for (i = 0; i < nrows + 3; i++) {
- Rast_set_null_value(cor[i], ncols + 3, DCELL_TYPE);
- }
- }
- /* if a map of patch numbers was requested,
- dynamically allocate storage for the
- buffer that will temporarily hold the map */
- if (choice->patchmap) {
- pat = (CELL **) G_calloc(nrows + 3, sizeof(CELL *));
- for (i = 0; i < nrows + 3; i++)
- pat[i] = (CELL *) Rast_allocate_buf(CELL_TYPE);
- }
- /* clip out the sampling area */
- cell_clip(buf, null_buf, row0, col0, nrows, ncols, index, radius,
- ¢ernull, &empty);
- /* if the clipped area is not all null values
- trace the patches in the sampling area; if
- a moving window is used, then the center
- pixel must also not be null */
- if (!empty) {
- if (choice->wrum != 'm') {
- trace(nrows, ncols, buf, null_buf, pat, cor);
- }
- else {
- if (!centernull)
- trace(nrows, ncols, buf, null_buf, pat, cor);
- }
- }
- /* if a map of patch cores was requested */
- if (choice->coremap) {
- /* 1. open the source map, then read the
- supporting files (cell header, colors,
- categories, history, quant) into the
- corresponding data structures */
- infd = Rast_open_old(name, mapset);
- colr_ok = Rast_read_colors(name, mapset, &colr) > 0;
- cats_ok = Rast_read_cats(name, mapset, &cats) >= 0;
- hist_ok = Rast_read_history(name, mapset, &hist) >= 0;
- range_ok = Rast_read_range(name, mapset, &range) >= 0;
- /* 2. if map is floating point, then read
- the rules for quantization into the quant
- data structure; if rules do not exist, create
- them by rounding floating point values */
- if (data_type != CELL_TYPE) {
- Rast_quant_init(&quant);
- if (Rast_read_quant(name, mapset, &quant) <= 0)
- Rast_quant_round(&quant);
- }
- /* 3. initialize appropriate data structures */
- if (cats_ok)
- Rast_init_cats(Rast_get_cats_title(&cats), &newcats);
- if (data_type == CELL_TYPE)
- Rast_init_cell_stats(&stats);
- /* 4. open an output map called "interior" and
- copy the contents of the core buffer into
- this output map */
- switch (data_type) {
- case CELL_TYPE:
- cor_cell_buf = Rast_allocate_buf(CELL_TYPE);
- fe = Rast_open_new("interior", CELL_TYPE);
- for (i = 1; i < nrows + 1; i++) {
- Rast_zero_buf(cor_cell_buf, CELL_TYPE);
- for (j = 1; j < ncols + 1; j++)
- *(cor_cell_buf + j - 1) = (int)(*(*(cor + i) + j));
- if (Rast_put_row(fe, cor_cell_buf, CELL_TYPE) < 0)
- exit(EXIT_FAILURE);
- Rast_update_cell_stats(cor_cell_buf, ncols + 1, &stats);
- }
- break;
- case FCELL_TYPE:
- cor_fcell_buf = Rast_allocate_buf(FCELL_TYPE);
- fe = Rast_open_new("interior", FCELL_TYPE);
- for (i = 1; i < nrows + 1; i++) {
- Rast_zero_buf(cor_fcell_buf, FCELL_TYPE);
- for (j = 1; j < ncols + 1; j++) {
- *(cor_fcell_buf + j - 1) = (float)(*(*(cor + i) + j));
- }
- if (Rast_put_row(fe, cor_fcell_buf, FCELL_TYPE) < 0)
- exit(EXIT_FAILURE);
- }
- break;
- case DCELL_TYPE:
- cor_dcell_buf = Rast_allocate_buf(DCELL_TYPE);
- fe = Rast_open_new("interior", DCELL_TYPE);
- for (i = 1; i < nrows + 1; i++) {
- Rast_zero_buf(cor_dcell_buf, DCELL_TYPE);
- for (j = 1; j < ncols + 1; j++)
- *(cor_dcell_buf + j - 1) = (double)(*(*(cor + i) + j));
- if (Rast_put_row(fe, cor_dcell_buf, DCELL_TYPE) < 0)
- exit(EXIT_FAILURE);
- }
- break;
- }
- }
- /* if a map of patch numbers was requested,
- complete the details of map creation */
- if (choice->patchmap) {
- fd = Rast_open_new("num", CELL_TYPE);
- for (i = 1; i < nrows + 1; i++) {
- pat_buf = Rast_allocate_buf(CELL_TYPE);
- Rast_zero_buf(pat_buf, CELL_TYPE);
- for (j = 1; j < ncols + 1; j++)
- *(pat_buf + j - 1) = *(*(pat + i) + j);
- if (Rast_put_row(fd, pat_buf, CELL_TYPE) < 0)
- exit(EXIT_FAILURE);
- }
- }
- /* print out the patch list */
- /* printf("\nPatch list after tracing\n");
- list_head = patch_list;
- while(list_head) {
- printf("num=%d att=%f pts=%d long=%3.0f crow=%3.0f ccol=%3.0f n=%d s=%d
- e=%d w=%d area=%3.0f per=%3.0f core=%3.0f edge=%3.0f\n",list_head->num,
- list_head->att,
- list_head->npts, list_head->long_axis, list_head->c_row,
- list_head->c_col, list_head->n,list_head->s,list_head->e,list_head->w,
- list_head->area, list_head->perim, list_head->core, list_head->edge);
- for (i=0; i<list_head->npts; i++) {
- printf("point[%d] row=%d col=%d\n",i,*(list_head->row +
- i),*(list_head->col + i));
- }
- list_head = list_head->next;
- }
- */
- /* if moving window method selected, then
- call the moving window driver program */
- if (choice->wrum == 'm') {
- if (!empty) {
- if (!centernull)
- mv_patch(patch_list, value, index);
- else {
- for (p = 0; p < 42; p++)
- *(*(value + index) + p) = -BIG;
- }
- }
- else {
- for (p = 0; p < 42; p++)
- *(*(value + index) + p) = -BIG;
- }
- }
- /* otherwise call the other driver program */
- else {
- if (!empty)
- df_patch(patch_list);
- }
- /* free memory allocated for content buffer */
- for (i = 0; i < nrows + 3; i++)
- G_free(buf[i]);
- G_free(buf);
- /* free memory allocated for null buffer */
- for (i = 0; i < nrows + 3; i++)
- G_free(null_buf[i]);
- G_free(null_buf);
- /* free memory allocated for num map */
- if (choice->patchmap) {
- for (i = 0; i < nrows + 3; i++)
- G_free(pat[i]);
- G_free(pat);
- }
- /* free memory allocated for core map */
- if (choice->coremap) {
- for (i = 0; i < nrows + 3; i++)
- G_free(cor[i]);
- G_free(cor);
- }
- /* free memory allocated for patch list */
- if (total_patches) {
- list_head = patch_list;
- while (list_head) {
- G_free(list_head->col);
- G_free(list_head->row);
- G_free(list_head);
- list_head = list_head->next;
- }
- }
- /* close the num file and release the
- memory allocated for it */
- if (choice->patchmap) {
- Rast_close(fd);
- G_free(pat_buf);
- }
- /* close the core file, copy the category
- information, the statistics, the color
- table, and the history over to map
- "interior" and then release the
- memory allocated for the cor_buf */
- if (choice->coremap) {
- Rast_close(fe);
- Rast_rewind_cell_stats(&stats);
- Rast_rewind_cats(&cats);
- if (cats_ok && data_type == CELL_TYPE) {
- long count;
- void *rast1, *rast2;
- rast1 = cor_cell_buf;
- rast2 = G_incr_void_ptr(rast1, Rast_cell_size(CELL_TYPE));
- while (Rast_next_cell_stat(rast1, &count, &stats))
- Rast_set_cat(rast1, rast2, Rast_get_cat(rast1, &cats,
- CELL_TYPE),
- &newcats, CELL_TYPE);
- Rast_write_cats("interior", &newcats);
- Rast_free_cats(&cats);
- Rast_free_cats(&newcats);
- Rast_free_cell_stats(&stats);
- }
- if (colr_ok) {
- if (data_type == CELL_TYPE) {
- CELL min, max, cmin, cmax;
- Rast_read_range("interior", mapset, &range);
- Rast_get_range_min_max(&range, &min, &max);
- Rast_get_c_color_range(&cmin, &cmax, &colr);
- if (min > cmin)
- cmin = min;
- if (max < cmax)
- cmax = max;
- Rast_set_c_color_range(cmin, cmax, &colr);
- }
- else {
- DCELL dmin, dmax;
- CELL cmin, cmax;
- Rast_read_fp_range("interior", mapset, &fprange);
- Rast_get_fp_range_min_max(&fprange, &dmin, &dmax);
- Rast_get_c_color_range(&cmin, &cmax, &colr);
- if (dmin > cmin)
- cmin = dmin;
- if (dmax < cmax)
- cmax = dmax;
- Rast_set_c_color_range(cmin, cmax, &colr);
- }
- Rast_write_colors("interior", mapset, &colr);
- }
- if (range_ok) {
- if (data_type == CELL_TYPE)
- Rast_write_range("interior", &range);
- else
- Rast_write_fp_range("interior", &fprange);
- }
- if (hist_ok)
- Rast_write_history("interior", &hist);
- Rast_free_cats(&cats);
- Rast_free_colors(&colr);
- switch (data_type) {
- case CELL_TYPE:
- G_free(cor_cell_buf);
- break;
- case FCELL_TYPE:
- G_free(cor_fcell_buf);
- break;
- case DCELL_TYPE:
- G_free(cor_dcell_buf);
- break;
- }
- }
- return;
- }
- /* OPEN THE RASTER FILE TO BE CLIPPED,
- AND DO THE CLIPPING */
- void cell_clip(DCELL ** buf, DCELL ** null_buf, int row0, int col0, int nrows,
- int ncols, int index, float radius, int *centernull,
- int *empty)
- {
- CELL *tmp, *tmp1;
- FCELL *ftmp;
- DCELL *dtmp;
- void *rastptr;
- char *tmpname;
- int fr, x;
- register int i, j;
- double center_row = 0.0, center_col = 0.0;
- double dist;
- RASTER_MAP_TYPE data_type;
- /*
- Variables:
- IN:
- buf = pointer to array containing only the pixels inside the area
- that was specified to be clipped, so a smaller array than the
- original raster map
- null_buf = pointer to array containing 0.0 if pixel in input raster map is
- not null and 1.0 if pixel in input raster map is null
- row0 = starting row for the area to be clipped out of the raster map
- col0 = starting col for the area to be clipped out of the raster map
- nrows = total number of rows in the area to be clipped
- ncols = total number of cols in the area to be clipped
- index = number of the region to be clipped, if there's a region map
- radius = radius of the circle to be clipped, if circles chosen for
- sampling units
- centernull = 1 if the center pixel of the clipped area is a null value,
- 0 otherwise
- empty = 1 is the whole clipped area contains null values, 0 otherwise.
- INTERNAL:
- tmp = pointer to a temporary buffer to store a row of a CELL_TYPE
- (integer) raster
- ftmp = pointer to a temporary buffer to store a row of an FCELL_TYPE
- (floating point) raster
- dtmp = pointer to a temporary buffer to store a row of a DCELL_TYPE
- (double) raster
- tmp1 = pointer to a temporary buffer to store a row of the region map
- tmpname = one of the above: tmp, ftmp, dtmp
- fr = return value from attempting to open the region map
- i, j = indices to rows and cols of the arrays
- center_row = row of the center of the circle, if circles used
- center_col = column of the center of the circle, if circles used
- dist = used to measure distance from a row/column to the center of the
- circle, to see if a row/column is within the circle
- data_type = the type of raster map: integer, floating point, or double
- rastptr = void pointer used to advance through null values in the tmp,
- ftmp, or dtmp buffers
- */
- /* if sampling by region was chosen, check
- for the region map and make sure it is
- an integer (CELL_TYPE) map */
- if (choice->wrum == 'r') {
- if (0 > (fr = Rast_open_old(choice->reg, G_mapset()))) {
- fprintf(stderr, "\n");
- fprintf(stderr,
- " *******************************************************\n");
- fprintf(stderr,
- " You specified sam=r to request sampling by region, \n");
- fprintf(stderr,
- " but the region map specified with the 'reg=' parameter\n");
- fprintf(stderr,
- " cannot be found in the current mapset. \n");
- fprintf(stderr,
- " *******************************************************\n");
- exit(EXIT_FAILURE);
- }
- if (Rast_map_type(choice->reg, G_mapset()) > 0) {
- fprintf(stderr, "\n");
- fprintf(stderr,
- " *******************************************************\n");
- fprintf(stderr,
- " You specified sam=r to request sampling by region, \n");
- fprintf(stderr,
- " but the region map specified with the 'reg=' parameter\n");
- fprintf(stderr,
- " must be an integer map, and it is floating point or \n");
- fprintf(stderr,
- " double instead. \n");
- fprintf(stderr,
- " *******************************************************\n");
- exit(EXIT_FAILURE);
- }
- tmp1 = Rast_allocate_buf(CELL_TYPE);
- Rast_zero_buf(tmp1, CELL_TYPE);
- fprintf(stderr, "Analyzing region number %d...\n", index);
- }
- data_type = Rast_map_type(choice->fn, G_mapset());
- /* allocate memory to store a row of the
- raster map, depending on the type of
- input raster map; keep track of the
- name of the buffer for each raster type */
- switch (data_type) {
- case CELL_TYPE:
- tmp = Rast_allocate_buf(CELL_TYPE);
- tmpname = "tmp";
- break;
- case FCELL_TYPE:
- ftmp = Rast_allocate_buf(FCELL_TYPE);
- tmpname = "ftmp";
- break;
- case DCELL_TYPE:
- dtmp = Rast_allocate_buf(DCELL_TYPE);
- tmpname = "dtmp";
- break;
- }
- /* zero the buffer used to hold null values */
- for (i = 0; i < nrows; i++) {
- for (j = 0; j < ncols; j++) {
- null_buf[i][j] = 1.0;
- }
- }
- /* if circles are used for sampling, then
- calculate the center of the area to be
- clipped, in pixels */
- if ((int)radius) {
- center_row = ((double)row0 + ((double)nrows - 1) / 2);
- center_col = ((double)col0 + ((double)ncols - 1) / 2);
- }
- /* for each row of the area to be clipped */
- /*printf("\n\nNEW WINDOW\n"); */
- for (i = row0; i < row0 + nrows; i++) {
- /* if region, read in the corresponding
- map row in the region file */
- if (choice->wrum == 'r')
- Rast_get_row_nomask(fr, tmp1, i, CELL_TYPE);
- /* initialize each element of the
- row buffer to 0; this row buffer
- will hold one row of the clipped
- raster map. Then read row i of the
- map into tmp buffer */
- switch (data_type) {
- case CELL_TYPE:
- Rast_zero_buf(tmp, data_type);
- Rast_get_row(finput, tmp, i, data_type);
- break;
- case FCELL_TYPE:
- Rast_zero_buf(ftmp, data_type);
- Rast_get_row(finput, ftmp, i, data_type);
- break;
- case DCELL_TYPE:
- Rast_zero_buf(dtmp, data_type);
- Rast_get_row(finput, dtmp, i, data_type);
- break;
- }
- /* set up a void pointer to be used to find null
- values in the area to be clipped and advance
- the raster pointer to the right starting
- column */
- switch (data_type) {
- case CELL_TYPE:
- rastptr = tmp;
- for (x = 0; x < col0; x++)
- rastptr = G_incr_void_ptr(rastptr, Rast_cell_size(CELL_TYPE));
- break;
- case FCELL_TYPE:
- rastptr = ftmp;
- for (x = 0; x < col0; x++)
- rastptr = G_incr_void_ptr(rastptr, Rast_cell_size(FCELL_TYPE));
- break;
- case DCELL_TYPE:
- rastptr = dtmp;
- for (x = 0; x < col0; x++)
- rastptr = G_incr_void_ptr(rastptr, Rast_cell_size(DCELL_TYPE));
- break;
- }
- /* for all the columns one by one */
- for (j = col0; j < col0 + ncols; j++) {
- /* look for null values in each cell
- and set centernull flag to 1 if
- center is null and empty to 1 if
- no cells are found that are not null */
- switch (data_type) {
- case CELL_TYPE:
- if (Rast_is_null_value(rastptr, CELL_TYPE)) {
- *(*(null_buf + i + 1 - row0) + j + 1 - col0) = 1.0;
- if (i == row0 + nrows / 2 && j == col0 + ncols / 2)
- *centernull = 1;
- }
- else {
- *empty = 0;
- if (choice->wrum != 'r' || *(tmp1 + j) == index)
- *(*(null_buf + i + 1 - row0) + j + 1 - col0) = 0.0;
- else
- *(*(null_buf + i + 1 - row0) + j + 1 - col0) = 1.0;
- }
- rastptr = G_incr_void_ptr(rastptr, Rast_cell_size(CELL_TYPE));
- break;
- case FCELL_TYPE:
- if (Rast_is_null_value(rastptr, FCELL_TYPE)) {
- *(*(null_buf + i + 1 - row0) + j + 1 - col0) = 1.0;
- if (i == row0 + nrows / 2 && j == col0 + ncols / 2)
- *centernull = 1;
- }
- else {
- *empty = 0;
- if (choice->wrum != 'r' || *(tmp1 + j) == index)
- *(*(null_buf + i + 1 - row0) + j + 1 - col0) = 0.0;
- else
- *(*(null_buf + i + 1 - row0) + j + 1 - col0) = 1.0;
- }
- rastptr = G_incr_void_ptr(rastptr, Rast_cell_size(FCELL_TYPE));
- break;
- case DCELL_TYPE:
- if (Rast_is_null_value(rastptr, DCELL_TYPE)) {
- *(*(null_buf + i + 1 - row0) + j + 1 - col0) = 1.0;
- if (i == row0 + nrows / 2 && j == col0 + ncols / 2)
- *centernull = 1;
- }
- else {
- *empty = 0;
- if (choice->wrum != 'r' || *(tmp1 + j) == index)
- *(*(null_buf + i + 1 - row0) + j + 1 - col0) = 0.0;
- else
- *(*(null_buf + i + 1 - row0) + j + 1 - col0) = 1.0;
- }
- rastptr = G_incr_void_ptr(rastptr, Rast_cell_size(CELL_TYPE));
- break;
- }
- /* if circles are used for sampling */
- if ((int)radius) {
- dist =
- sqrt(((double)i - center_row) * ((double)i - center_row) +
- ((double)j - center_col) * ((double)j - center_col));
- /* copy the contents of the correct tmp file
- into the appropriate cell in the buf */
- if (dist < radius) {
- switch (data_type) {
- case CELL_TYPE:
- *(*(buf + i + 1 - row0) + j + 1 - col0) = *(tmp + j);
- break;
- case FCELL_TYPE:
- *(*(buf + i + 1 - row0) + j + 1 - col0) = *(ftmp + j);
- break;
- case DCELL_TYPE:
- *(*(buf + i + 1 - row0) + j + 1 - col0) = *(dtmp + j);
- break;
- }
- }
- else
- *(*(null_buf + i + 1 - row0) + j + 1 - col0) = 1.0;
- }
- /* if circles are not used and
- if the choice is not "by region" or
- if this column is in region "index" */
- else if (choice->wrum != 'r' || *(tmp1 + j) == index) {
- /* copy the contents of the correct tmp
- into the appropriate cell in the buf
- and the corresponding null values into
- the appropriate cell in null_buf */
- switch (data_type) {
- case CELL_TYPE:
- *(*(buf + i + 1 - row0) + j + 1 - col0) = *(tmp + j);
- break;
- case FCELL_TYPE:
- *(*(buf + i + 1 - row0) + j + 1 - col0) = *(ftmp + j);
- break;
- case DCELL_TYPE:
- *(*(buf + i + 1 - row0) + j + 1 - col0) = *(dtmp + j);
- break;
- }
- /*printf("cell_clip i=%d j=%d buf= %12.0f null_buf = %d\n", i, j,
- *(*(buf +i+1-row0)+j+1-col0), *(*(null_buf +i +1-row0) +j +1 -col0)); */
- }
- }
- }
- switch (data_type) {
- case CELL_TYPE:
- G_free(tmp);
- break;
- case FCELL_TYPE:
- G_free(ftmp);
- break;
- case DCELL_TYPE:
- G_free(dtmp);
- break;
- }
- if (choice->wrum == 'r') {
- G_free(tmp1);
- Rast_close(fr);
- }
- return;
- }
- /* DRIVER TO LOOK FOR NEW PATCHES, CALL
- THE TRACING ROUTINE, AND ADD NEW PATCHES
- TO THE PATCH LIST */
- void trace(int nrows, int ncols, DCELL ** buf, DCELL ** null_buf, CELL ** pat,
- DCELL ** cor)
- {
- double class = 0.0;
- register int i, j;
- PATCH *tmp, *find_any, *list_head;
- /*
- Variables:
- EXTERN:
- IN:
- nrows = total number of rows in the area where tracing will occur
- ncols = total number of cols in the area where tracing will occur
- buf = pointer to array containing only the pixels inside the area
- that was clipped and within which tracing will now occur, so
- a smaller array than the original raster map
- null_buf = pointer to array containing 0.0 if pixel in input raster map is
- not null and 1.0 if pixel in input raster map is null
- pat = pointer to array containing the map of patch numbers; this map
- can only be integer
- cor = pointer to array containing the map of interior area; this map
- can be integer, floating point, or double, but is stored as a
- double throughout the program
- INTERNAL:
- class = the attribute of each pixel
- i, j = counts the row and column as the program goes through the area
- tmp = pointer to a member of the PATCH list data structure, used to
- advance through the patch list
- find_any = pointer to a member of the patch list to hold the results after
- routine get_bd is called to trace the boundary of the patch and
- save the patch information in the PATCH data structure
- list_head = pointer to the first member of the patch list
- */
- /* go thru buf, which contains the entries
- within the clipped window, column by
- column and row by row; Note that now the
- rows and cols are counted from 1 to nrows
- and 1 to ncols, not from 0 to < nrows and
- 0 to < ncols */
- i = 0;
- while (i++ < nrows) { /*1 */
- j = 0;
- while (j++ < ncols) {
- /* if this pt contains a positive or negative
- raster value or a zero, and null value is
- 0.0, it may be the start of an untraced
- patch */
- if ((*(*(buf + i) + j) || *(*(buf + i) + j) == 0.0) && *(*(null_buf + i) + j) == 0.0) { /*3 */
- class = *(*(buf + i) + j);
- /* trace the patch from the current pt */
- list_head = patch_list;
- if ((find_any = get_bd(i, j, nrows, ncols, class, buf, null_buf, list_head, pat, cor))) { /*4 */
- /* if the first patch, make tmp point to
- the patch list and add the first patch
- to the list */
- if (total_patches == 0) {
- patch_list = find_any;
- tmp = patch_list;
- }
- /* add the next patch to the patch list */
- else {
- tmp->next = find_any;
- tmp = tmp->next;
- }
- /* increment the count of total patches */
- total_patches++;
- } /*4 */
- /* if i and j are now at or outside the
- limits of the window, then quit */
- if (i >= nrows && j >= ncols) {
- return;
- }
- } /*3 */
- /* if this pt is the boundary point of an
- already traced patch or is outside the
- window, do not start tracing; skip to
- next pt */
- else { /*5 */
- /* if i and j are now at or outside the
- limits of the window, then quit */
- if (i >= nrows && j >= ncols)
- return;
- } /*5 */
- } /*2 */
- }
- return; /*1 */
- }
- /* TRACE THE BOUNDARY OF A PATCH AND
- SAVE THE PATCH CHARACTERISTICS IN
- THE PATCH STRUCTURE */
- PATCH *get_bd(int row0, int col0, int nrows, int ncols, double class,
- DCELL ** buf, DCELL ** null_buf, PATCH * p_list, CELL ** pat,
- DCELL ** cor)
- {
- int i = row0, j = col0, pts = 0, di = 0, dj = -1,
- not_done, k, m, tmp, lng = 0, roww = 0, rowe = 0,
- row1, col1, di2, dj2, p, q, area, per, corearea, edgearea, nozero;
- int ***twist2, trows, tcols, n, e, a, b;
- float ***twistP, sumT;
- PATCH *patch;
- CELL **patchmap;
- PT *ptrfirst, *ptrthis, *ptrnew, *ptrfree;
- /*
- Variables:
- IN:
- row0 = row for the first pixel in the patch
- col0 = column for the first pixel in the patch
- nrows = number of rows in the clipped area
- ncols = number of columns in the clipped area
- class = attribute of the patch being traced
- buf = pointer to array containing only the pixels inside the area
- that was clipped
- null_buf = pointer to array containing 0.0 if pixel in input raster map is
- not null and 1.0 if pixel in input raster map is null
- p_list = pointer to the patch list
- pat = pointer to array containing the map of patch numbers; this map
- can only be integer
- cor = pointer to array containing the map of interior area; this map
- can be integer, floating point, or double, but is stored as a
- double throughout the program
- INTERNAL
- i, j = counts the row and column as tracing occurs
- pts = counts the number of points as tracing proceeds
- di, dj = indicates moves of 1 pixel in the row or column direction, used
- to examine adjoining 4- or 8-neighboring pixels when tracing
- not_done = flag to indicate when the patch has not been fully traced yet
- k =
- m =
- tmp = integer to hold intermediate results in calculation of long axis
- of patch
- lng = integer to hold the calculated long axis of the patch
- roww = integer to hold the westernmost point in each row of the patch
- rowe = integer to hold the easternmost point in each row of the patch
- coln = integer to hold the northernmost point in each row of the patch
- cols = integer to hold the southernmost point in each row of the patch
- row1 = integer to hold the starting row for tracing internal boundaries
- col1 = integer to hold the starting column for tracing internal boundaries
- di2, dj2 = indicates moves of 1 pixel in the row or column direction, used
- to examine adjoining 4- or 8-neighboring pixels when tracing
- internal boundaries of a patch
- p, q = row and column indices for tracing patch internal boundaries
- area = patch area
- per = patch perimeter
- corearea = patch interior area
- edgearea = patch edge area
- nozero =
- twist2 = 2-dimensional array to hold preliminary countes needed to calculate
- the twist number and omega index
- trows = number of rows in the bounding box for the patch
- tcols = number of columns in the bounding box for the patch
- n, e = northing (in rows) and easting (in columns) for the patch
- a, b = indexes particular pixels used in calculating twist number in certain
- cases
- twistnum = twist number
- twistP = 2-dimensional array to hold P values used in the calculation of twist
- number
- sumT = the floating point version of twist number
- omega = omega index
- patch = pointer to a member of the patch list
- patchmap = 2-dimensional array holding 1's for pixels inside the patch and
- zero otherwise
- ptrfirst = pointer to the first element of the linked list of patches
- ptrthis = pointer to the current element of the linked list of patches
- ptrnew = pointer to a new element of the linked list of patches
- ptrfree =
- */
- /* allocate memory for 1 patch to be
- saved in the patch data structure */
- patch = (PATCH *) G_calloc(1, sizeof(PATCH));
- /* allocate memory for patchmap, which
- will hold the patch boundaries found in
- the buf array */
- patchmap = (CELL **) G_calloc(nrows + 3, sizeof(CELL *));
- for (m = 0; m < nrows + 3; m++)
- patchmap[m] = (CELL *) Rast_allocate_buf(CELL_TYPE);
- /* print on the screen a message indicating
- that tracing has reached a certain patch */
- if (choice->wrum != 'm') {
- fprintf(stderr, "Tracing patch %7d\r", total_patches + 1);
- }
- /* if this is the first patch to be traced,
- then set the next patch on the patch list
- to NULL */
- if (total_patches == 0)
- patch->next = (PATCH *) NULL;
- /* this loop goes until the patch has been
- traced */
- for (;;) { /*1 */
- /* STEP 1: RECORD ATTRIBUTE AND PATCH NUMBER,
- THEN TRACE THE PTS IN THE BOUNDARY,
- RECORDING THE ROW AND COL OF EACH PT, AND
- FINDING THE PATCH BOUNDING BOX */
- /* initialize variables */
- not_done = 1;
- patch->s = 0;
- patch->e = 0;
- patch->w = (int)BIG;
- patch->n = (int)BIG;
- /* while tracing is not done */
- while (not_done) { /*2 */
- /* if this is the first pt in the patch,
- fill the PATCH structure with the
- attribute and number of the patch,
- and set the first pt to NULL */
- if (pts == 0) {
- patch->att = class;
- patch->num = total_patches + 1;
- ptrfirst = (PT *) NULL;
- }
- /* if this pt has a non-null value and
- it hasn't been traced.
- (1) put a 1 in patchmap at the location.
- This will keep track of all the pixels
- that get traced in this one patch.
- (2) make the null_buf value a 1.0. This
- will keep track of all the pixels that
- get traced or are otherwise null in all
- the patches in the buffer. Once they
- are null, they don't get traced again.
- (3) save the row & col in PATCH structure,
- (4) see if the pt expands the current
- bounding box
- (5) increment the pts count */
- /*printf("num=%d i=%d j=%d buf=%f patchmap=%d null=%f START GET_BD\n",
- patch->num,i,j,*(*(buf + i) + j),*(*(patchmap + i) + j), *(*(null_buf + i) +
- j)); */
- if ((*(*(buf + i) + j) ||
- *(*(buf + i) + j) == 0.0) &&
- *(*(patchmap + i) + j) == 0 &&
- *(*(null_buf + i) + j) == 0.0) {
- *(*(patchmap + i) + j) = 1;
- *(*(null_buf + i) + j) = 1.0;
- ptrnew = (PT *) G_calloc(1, sizeof(PT));
- if (ptrfirst == (PT *) NULL) {
- ptrfirst = ptrthis = ptrnew;
- }
- else {
- ptrthis = ptrfirst;
- while (ptrthis->next != (PT *) NULL)
- ptrthis = ptrthis->next;
- ptrthis->next = ptrnew;
- ptrthis = ptrnew;
- }
- ptrthis->row = i;
- ptrthis->col = j;
- if (i > patch->s)
- patch->s = i;
- if (i < patch->n)
- patch->n = i;
- if (j > patch->e)
- patch->e = j;
- if (j < patch->w)
- patch->w = j;
- pts++;
- }
- /*printf("3. i=%d j=%d s=%d n=%d w=%d e=%d\n",i,j, patch->s, patch->n,
- patch->w,patch->e); */
- /* if there is a neighboring pixel, with the
- same class, moving clockwise around the
- patch, then reset i and j to this
- location, then reset di and dj */
- if (yes_nb(&di, &dj, buf, class, i, j, nrows, ncols)) {
- i = i + di;
- j = j + dj;
- di = -di;
- dj = -dj;
- clockwise(&di, &dj);
- /*printf("num=%d i=%d j=%d buf=%f patchmap=%d null=%d row0=%d col0=%d \
- AFTER YES_NB\n",
- patch->num,i,j, *(*(buf + i) + j), *(*(patchmap + i) + j),
- *(*(null_buf + i) + j), row0, col0);
- */
- /* if tracing has returned to the starting
- pt, then stop; in a special case with
- diagonal tracing, don't stop if there is
- a traceable pixel below and to the left
- and if there is a below and to the left */
- if (i == row0 && j == col0) {
- not_done = 0;
- if (choice->trace &&
- (i < nrows) && (j > 1) &&
- *(*(buf + i + 1) + j - 1) == class &&
- (*(*(patchmap + i + 1) + j - 1) == 0) &&
- (*(*(null_buf + i + 1) + j - 1) == 0.0)) {
- /*printf("IN NOT DONE i=%d j=%d i=%d j=%d buf=%f patchmap=%d null_buf=%f\n",
- i,j,i+1,j-1,*(*(buf + i + 1) + j - 1),*(*(patchmap + i + 1) + j - 1),
- *(*(null_buf + i + 1) + j - 1)); */
- not_done = 1;
- }
- }
- }
- /* if there is no neighboring pixel with the
- same class, then stop tracing */
- else
- not_done = 0;
- } /*2 */
- /* STEP 2: CLEAN AND FILL THE PATCH WITHIN
- ITS BOUNDARIES. THE MAP IS CLEANED AND
- FILLED INTO "PATCHMAP" WHICH THEN CONTAINS
- THE FOLLOWING VALUES:
- 1 = BOUNDARY PT
- -999 = INTERIOR (NON BOUNDARY) PT */
- for (i = patch->n; i < patch->s + 1; i++) { /*3 */
- /* find the westernmost and easternmost boundary
- points in row i */
- roww = patch->w;
- rowe = patch->e;
- while (*(*(patchmap + i) + roww) == 0 && roww < patch->e)
- roww++;
- while (*(*(patchmap + i) + rowe) == 0 && rowe > patch->w)
- rowe--;
- /* if the westernmost and easternmost boundary
- pts in row i are not the same or are not
- next to each other, then we need to scan
- across row i */
- if (roww != rowe && roww + 1 != rowe) { /*4 */
- for (j = roww; j < rowe; j++) { /*5 */
- /* if this pixel is one of the traced boundary
- or interior pts and the next pixel in the row
- is not one of these or has not been traced, */
- if (*(*(patchmap + i) + j) != 0 && *(*(patchmap + i) + j + 1) == 0) { /*6 */
- /* if the next pixel has the same class, then
- give that pixel a -999 in patchmap to signify
- that it is part of the patch, and make null_buf
- a 1.0 to signify that this next pixel has been
- traced */
- if (*(*(buf + i) + j + 1) == class) {
- *(*(patchmap + i) + j + 1) = -999;
- *(*(null_buf + i) + j + 1) = 1.0;
- }
- /* but if the next pixel doesn't have the same
- class, then the present pixel marks the edge
- of a potential interior boundary for the patch.
- Trace this boundary only if it has not already
- been traced */
- else if (*(*(buf + i) + j + 1) != class && (*(*(patchmap + i) + j) != 1 || *(*(patchmap + i) + j + 1) == 0)) { /*7 */
- not_done = 1;
- row1 = p = i;
- col1 = q = j;
- di2 = 0;
- dj2 = 1;
- while (not_done) { /*8 */
- if (*(*(patchmap + p) + q) == -999)
- *(*(patchmap + p) + q) = 4;
- if (*(*(patchmap + p) + q) == 4) {
- ptrnew = (PT *) G_calloc(1, sizeof(PT));
- ptrthis = ptrfirst;
- while (ptrthis->next != (PT *) NULL)
- ptrthis = ptrthis->next;
- ptrthis->next = ptrnew;
- ptrthis = ptrnew;
- ptrthis->row = p;
- ptrthis->col = q;
- *(*(patchmap + p) + q) = 1;
- *(*(null_buf + p) + q) = 1.0;
- pts++;
- }
- if (yes_nb(&di2, &dj2, buf, class, p, q,
- nrows, ncols)) {
- p = p + di2;
- q = q + dj2;
- if (*(*(patchmap + p) + q) != 1) {
- *(*(patchmap + p) + q) = 4;
- *(*(null_buf + p) + q) = 1.0;
- }
- di2 = -di2;
- dj2 = -dj2;
- clockwise(&di2, &dj2);
- if (p == row1 && q == col1) {
- not_done = 0;
- }
- }
- else
- not_done = 0;
- } /*8 */
- } /*7 */
- } /*6 */
- } /*5 */
- } /*4 */
- } /*3 */
- /* STEP 3: GO THROUGH THE RESULTING PATCHMAP
- AND FIND THE INTERIOR & EDGE AREA IF REQUESTED */
- if (choice->core[0]) {
- for (k = 0; k < choice->edge; k++) {
- for (i = patch->n; i < patch->s + 1; i++) {
- for (j = patch->w; j < patch->e + 1; j++) {
- if ((k > 0 && *(*(patchmap + i) + j) == k) ||
- (k == 0 && *(*(patchmap + i) + j) == 1)) {
- /* if the sampling area border is not to
- be considered patch edge and we're
- interior of the sampling area border,
- then we can search for interior; OR if the
- sampling area border is to be considered
- patch edge, then we can search for interior */
- if ((choice->perim2 && i != 1 && i != nrows &&
- j != 1 && j != ncols) || !choice->perim2) {
- di = 0;
- dj = -1;
- for (m = 0; m < 8; m++) {
- if (*(*(patchmap + i + di) + j + dj) ==
- -999) {
- if (choice->trace) {
- if (k > 0)
- *(*(patchmap + i + di) + j +
- dj) = k + 1;
- }
- else if (di == 0 || dj == 0) {
- if (k > 0)
- *(*(patchmap + i + di) + j +
- dj) = k + 1;
- }
- }
- clockwise(&di, &dj);
- }
- }
- else {
- nozero = 1;
- if (j != 1)
- if (*(*(patchmap + i) + j - 1) == 0)
- nozero = 0;
- if (i != 1 && j != 1)
- if (*(*(patchmap + i - 1) + j - 1) == 0)
- nozero = 0;
- if (i != 1)
- if (*(*(patchmap + i - 1) + j) == 0)
- nozero = 0;
- if (i != 1 && j != ncols)
- if (*(*(patchmap + i - 1) + j + 1) == 0)
- nozero = 0;
- if (j != ncols)
- if (*(*(patchmap + i) + j + 1) == 0)
- nozero = 0;
- if (i != nrows && j != ncols)
- if (*(*(patchmap + i + 1) + j + 1) == 0)
- nozero = 0;
- if (i != nrows)
- if (*(*(patchmap + i + 1) + j) == 0)
- nozero = 0;
- if (i != nrows && j != 1)
- if (*(*(patchmap + i + 1) + j - 1) == 0)
- nozero = 0;
- if (nozero)
- *(*(patchmap + i) + j) = -999;
- }
- }
- }
- }
- }
- }
- /* STEP 4: GO THROUGH THE RESULTING PATCHMAP AND DETERMINE
- THE PATCH SIZE, AMOUNT OF PERIMETER AND, IF REQUESTED,
- THE CORE SIZE AND EDGE SIZE */
- area = 0;
- per = 0;
- corearea = 0;
- edgearea = 0;
- for (i = patch->n; i < patch->s + 1; i++) {
- for (j = patch->w; j < patch->e + 1; j++) {
- if (*(*(patchmap + i) + j) || *(*(patchmap + i) + j) == -999) {
- area++;
- if (choice->perim2 == 0) {
- if (j == 1 || j == ncols)
- per++;
- }
- if (j < ncols && *(*(patchmap + i) + j + 1) == 0)
- per++;
- if (j > 1 && *(*(patchmap + i) + j - 1) == 0)
- per++;
- /* if a num map was requested with the -n flag,
- then copy the patch numbers into pat array */
- if (choice->patchmap)
- *(*(pat + i) + j) = patch->num;
- /* if core calculations are requested */
- if (choice->core[0]) {
- if (*(*(patchmap + i) + j) == -999)
- corearea++;
- if (*(*(patchmap + i) + j) > 0)
- edgearea++;
- }
- /* if core map is requested */
- if (choice->coremap) {
- if (*(*(patchmap + i) + j) == -999)
- *(*(cor + i) + j) = *(*(buf + i) + j);
- }
- }
- }
- }
- for (j = patch->w; j < patch->e + 1; j++) {
- for (i = patch->n; i < patch->s + 1; i++) {
- if (*(*(patchmap + i) + j) || *(*(patchmap + i) + j) == -999) {
- if (choice->perim2 == 0) {
- if (i == 1 || i == nrows)
- per++;
- }
- if (i < nrows && *(*(patchmap + i + 1) + j) == 0)
- per++;
- if (i > 1 && *(*(patchmap + i - 1) + j) == 0)
- per++;
- }
- }
- }
- patch->area = area;
- patch->perim = per;
- patch->edge = edgearea;
- patch->core = corearea;
- /* STEP 5: GO THROUGH THE RESULTING LIST OF PTS,
- RECORD THE ROW AND COL IN THE PATCH
- STRUCTURE, AND FIND THE LONG AXIS AND
- CENTER OF THE PATCH */
- patch->npts = pts;
- /* allocate enough memory to store the list of
- pts in the PATCH structure */
- patch->col = (int *)G_calloc(pts, sizeof(int));
- patch->row = (int *)G_calloc(pts, sizeof(int));
- /* go through the list of pts */
- i = 0;
- ptrthis = ptrfirst;
- while (ptrthis) {
- ptrfree = ptrthis;
- /* save the pt locat. in the PATCH structure */
- *(patch->row + i) = ptrthis->row;
- *(patch->col + i) = ptrthis->col;
- /* long-axis step 1: find the largest
- sum of squares between patch boundary
- pts if the Related Circumscribing Circle
- shape index is requested */
- if (choice->Mx[3]) {
- if (pts == 1) {
- lng = 2;
- }
- else {
- for (j = 0; j < i + 1; j++) {
- if ((tmp =
- (abs(*(patch->row + j) - *(patch->row + i)) +
- 1) * (abs(*(patch->row + j) -
- *(patch->row + i)) + 1) +
- (abs(*(patch->col + j) - *(patch->col + i)) +
- 1) * (abs(*(patch->col + j) -
- *(patch->col + i)) + 1)) > lng)
- lng = tmp;
- }
- }
- }
- /* patch center step 1: sum up the boundary
- coordinates */
- if (i < pts) {
- patch->c_row += *(patch->row + i);
- patch->c_col += *(patch->col + i);
- }
- ptrthis = ptrthis->next;
- G_free(ptrfree);
- i++;
- }
- /* patch long axis and center step 2: complete
- the calculations */
- if (choice->Mx[3])
- patch->long_axis = sqrt((double)(lng));
- patch->c_col = (int)(patch->c_col / pts + 0.5);
- patch->c_row = (int)(patch->c_row / pts + 0.5);
- /* STEP 6: IF TWIST STATISTICS WERE REQUESTED, GO
- THROUGH THE PATCHMAP AND CALCULATE TWIST & OMEGA */
- if (choice->boundary[0]) {
- /* dynamically allocate storage for the arrays that will
- hold the twist tallies and P values */
- trows = patch->s - patch->n + 3;
- tcols = patch->e - patch->w + 3;
- twist2 = (int ***)G_calloc(trows + 3, sizeof(int **));
- for (i = 0; i < trows + 3; i++) {
- twist2[i] = (int **)G_calloc(tcols + 3, sizeof(int *));
- for (j = 0; j < tcols + 3; j++)
- twist2[i][j] = (int *)G_calloc(7, sizeof(int));
- }
- twistP = (float ***)G_calloc(trows + 3, sizeof(float **));
- for (i = 0; i < trows + 3; i++) {
- twistP[i] = (float **)G_calloc(tcols + 3, sizeof(float *));
- for (j = 0; j < tcols + 3; j++)
- twistP[i][j] = (float *)G_calloc(7, sizeof(float));
- }
- /* zero the twist2 and twistP matrices */
- for (i = 0; i < trows + 3; i++) {
- for (j = 0; j < tcols + 3; j++) {
- for (k = 0; k < 5; k++) {
- twist2[i][j][k] = 0;
- twistP[i][j][k] = 0.0;
- }
- }
- }
- /* fill the twist2 matrix with counts; do this for
- each pixel in the patch, identified by having a
- value of 1 or -999 */
- for (i = patch->n; i < patch->s + 1; i++) {
- for (j = patch->w; j < patch->e + 1; j++) {
- n = i - patch->n + 1;
- e = j - patch->w + 1;
- if (*(*(patchmap + i) + j) > 0 ||
- *(*(patchmap + i) + j) == -999) {
- if (*(*(patchmap + i) + j - 1) > 0 ||
- *(*(patchmap + i) + j - 1) == -999)
- twist2[n][e][0]++;
- if (*(*(patchmap + i - 1) + j - 1) > 0 ||
- *(*(patchmap + i - 1) + j - 1) == -999)
- twist2[n][e][0]++;
- if (*(*(patchmap + i - 1) + j) > 0 ||
- *(*(patchmap + i - 1) + j) == -999)
- twist2[n][e][0]++;
- if (*(*(patchmap + i - 1) + j) > 0 ||
- *(*(patchmap + i - 1) + j) == -999)
- twist2[n][e][1]++;
- if (*(*(patchmap + i - 1) + j + 1) > 0 ||
- *(*(patchmap + i - 1) + j + 1) == -999)
- twist2[n][e][1]++;
- if (*(*(patchmap + i) + j + 1) > 0 ||
- *(*(patchmap + i) + j + 1) == -999)
- twist2[n][e][1]++;
- if (*(*(patchmap + i) + j + 1) > 0 ||
- *(*(patchmap + i) + j + 1) == -999)
- twist2[n][e][2]++;
- if (*(*(patchmap + i + 1) + j + 1) > 0 ||
- *(*(patchmap + i + 1) + j + 1) == -999)
- twist2[n][e][2]++;
- if (*(*(patchmap + i + 1) + j) > 0 ||
- *(*(patchmap + i + 1) + j) == -999)
- twist2[n][e][2]++;
- if (*(*(patchmap + i + 1) + j) > 0 ||
- *(*(patchmap + i + 1) + j) == -999)
- twist2[n][e][3]++;
- if (*(*(patchmap + i + 1) + j - 1) > 0 ||
- *(*(patchmap + i + 1) + j - 1) == -999)
- twist2[n][e][3]++;
- if (*(*(patchmap + i) + j - 1) > 0 ||
- *(*(patchmap + i) + j - 1) == -999)
- twist2[n][e][3]++;
- /* calculate the P values based on the tallies */
- for (k = 0; k < 4; k++) {
- if (*(*(patchmap + i) + j) > 0 ||
- *(*(patchmap + i) + j) == -999) {
- if (twist2[n][e][k] - 1 < 0)
- twistP[n][e][k] = 1.0;
- else if (twist2[n][e][k] - 1 == 0) {
- if (k - 1 > 0)
- a = i + 1;
- else
- a = i - 1;
- if (k == 1 || k == 2)
- b = j + 1;
- else
- b = j - 1;
- if (*(*(patchmap + a) + b) > 0 ||
- *(*(patchmap + a) + b) == -999)
- twistP[n][e][k] = 1.0;
- else
- twistP[n][e][k] = 0.0;
- }
- else if (twist2[n][e][k] - 1 > 0) {
- if (twist2[n][e][k] == 3)
- twistP[n][e][k] = 0.0;
- else if (twist2[n][e][k] == 2)
- twistP[n][e][k] = .33333;
- }
- }
- }
- }
- }
- }
- /* sum up the P values to calculate the twist number */
- sumT = 0.0;
- for (n = 0; n < trows; n++) {
- for (e = 0; e < tcols; e++) {
- for (k = 0; k < 4; k++)
- sumT = sumT + twistP[n][e][k];
- }
- }
- patch->twist = (int)(sumT + 0.5);
- /* calculate the omega index for 3 cases, depending upon
- whether 8-neighbor or 4-neighbor tracing was chosen */
- if (choice->trace) {
- if (patch->area > 1.0)
- patch->omega = (4.0 * patch->area - (float)patch->twist) /
- (4.0 * patch->area - 4.0);
- else
- patch->omega = 0.0;
- }
- else {
- if ((((int)patch->area % 4) - 1) == 0) {
- if (patch->area > 1.0)
- patch->omega =
- (2.0 * patch->area + 2.0 -
- (float)patch->twist) / (2.0 * patch->area - 2.0);
- else
- patch->omega = 0.0;
- }
- else
- patch->omega = (2.0 * patch->area - (float)patch->twist) /
- (2.0 * patch->area - 4.0);
- }
- /*printf("twistnum = %4d omega=%6.4f area=%7.0f\n", patch->twist,
- patch->omega,patch->area); */
- /* free memory allocated for holding twist tallies and
- P values */
- for (i = 0; i < trows + 3; i++) {
- for (j = 0; j < tcols + 3; j++)
- G_free(twistP[i][j]);
- G_free(twistP[i]);
- }
- G_free(twistP);
- for (i = 0; i < trows + 3; i++) {
- for (j = 0; j < tcols + 3; j++)
- G_free(twist2[i][j]);
- G_free(twist2[i]);
- }
- G_free(twist2);
- }
- /* STEP 7: MAKE NEXT PATCH NULL, FREE MEMORY,
- AND RETURN THE PATCH STRUCTURE */
- patch->next = (PATCH *) NULL;
- /* free the memory allocated for patchmap */
- for (i = 0; i < nrows + 3; i++)
- G_free(patchmap[i]);
- G_free(patchmap);
- /* send the patch info back to trace */
- return (patch);
- } /*1 */
- }
- /* SEARCH THE 8 NEIGHBORS OF A PIXEL IN
- THE BUFFER IN A CLOCKWISE DIRECTION
- LOOKING FOR A PIXEL WITH THE SAME
- CLASS AND RETURN A 1 AND DI, DJ FOR
- THE FIRST PIXEL FOUND; OTHERWISE RETURN
- A ZERO */
- int yes_nb(int *di, int *dj, DCELL ** buf, double class, int i, int j,
- int nrows, int ncols)
- {
- /* di=0 to start; di is the value to be added to i to get to the
- pixel with the same value
- dj=-1 to start; dj is the value to be added to j to get to the
- pixel with the same value
- class = the attribute of the center pixel
- */
- register int k;
- /*printf("1i=%d di=%d j=%d dj=%d nrows=%d
- ncols=%d\n",i,*di,j,*dj,nrows,ncols); */
- /* if tracing is to include crossing to
- diagonal pixels */
- if (choice->trace) { /*1 */
- /* search through the 8 neighbor pixels */
- for (k = 0; k < 8; k++) {
- /* if the neighbor pixel has the same
- attribute as that of the current pixel,
- then it may be part of the patch.
- Confine the search to only pixels
- inside the buffer to avoid a crash! */
- if ((i + *di > 0) && (j + *dj > 0) &&
- (i + *di <= nrows) && (j + *dj <= ncols)) {
- if (class == *(*(buf + i + *di) + j + *dj))
- return 1;
- }
- clockwise(di, dj);
- }
- /* if no neighbor with the same class is found,
- then we are done tracing the patch */
- return 0;
- } /*1 */
- /* if tracing is not to include crossing to
- diagonal pixels */
- else {
- /* search through the 8 neighbor pixels */
- for (k = 0; k < 8; k++) {
- /* if the neighbor pixel has the same
- attribute as that of the current pixel,
- then maybe it is part of the same patch */
- if ((i + *di > 0) && (j + *dj > 0) &&
- (i + *di <= nrows) && (j + *dj <= ncols)) {
- if (class == *(*(buf + i + *di) + j + *dj)) {
- /* if the neighbor pixel is directly above,
- below, to the right or left of the current
- pixel then tracing can continue */
- if (*di == 0 || *dj == 0)
- return 1;
- /* next check the diagonal neighbors
- that have a bishops pattern and if
- they have an adjacent pixel with the same
- class then continue tracing, as they are
- not isolated diagonal pixels */
- /* lower left bishops pattern */
- if (*di == 1 && *dj == -1)
- if ((class == *(*(buf + i + *di) + j)) ||
- (class == *(*(buf + i) + j + *dj)))
- return 1;
- /* upper left bishops pattern */
- if (*di == -1 && *dj == -1)
- if ((class == *(*(buf + i + *di) + j)) ||
- (class == *(*(buf + i) + j + *dj)))
- return 1;
- /* upper right bishops pattern */
- if (*di == -1 && *dj == 1)
- if ((class == *(*(buf + i + *di) + j)) ||
- (class == *(*(buf + i) + j + *dj)))
- return 1;
- /* lower right bishops pattern */
- if (*di == 1 && *dj == 1)
- if ((class == *(*(buf + i + *di) + j)) ||
- (class == *(*(buf + i) + j + *dj)))
- return 1;
- }
- }
- /* if the neighbor pixel has a different
- class or it is not in the
- same row or col and is an isolated
- bishops pattern pixel, then don't
- trace it, but go to the next one
- of the 8 neighbors */
- clockwise(di, dj);
- }
- /* if all the neighbors are isolated
- bishops pattern pixels or no
- neighbor with the same class is found
- then we are done tracing the patch */
- return (0);
- }
- }
- /* CIRCLE CLOCKWISE AROUND THE CURRENT PT */
- void clockwise(int *i, int *j)
- {
- if (*i != 0 && *j != -*i)
- *j -= *i;
- else
- *i += *j;
- return;
- }
|