ISCE_INSAR/components/mroipac/grass/src/trees.c

425 lines
15 KiB
C

#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <stdio.h>
#include "defines.h"
int nearest_tree(unsigned char **, int, int, int) ;
void start_timing(); /* timing routines */
void stop_timing();
/**
* @param flagFilename phase unwrapping flag file name
* @param width number of samples per row
* @param mbl maximum branch length (default=64)
* @param start starting line (default=1)
* @param xmin starting range pixel offset
* @param xmax last range pixel offset
* @param ymin starting azimuth row
* @param ymax last azimuth row
*/
int
trees(char *flagFilename, int width, int mbl, int start, int xmin, int xmax, int ymin, int ymax)
{
int nlines; /* number of lines in the file */
int xw,yh; /* width, height of processed region */
int offs; /* offset number of lines to read from start of file*/
int i;
int r_chrg; /* residual charge */
unsigned char *fbf; /* flag array */
unsigned char **gzw; /* set of pointers to the rows of flag array */
FILE *flag_file;
double Pi=4*atan2(1,1);
flag_file = fopen(flagFilename,"r+");
if (flag_file == NULL){
fprintf(stderr, "flag file does not exist!\n");
exit(-1);
}
if (xmax <=0) {
xmax=width-1; /* default value of xmax */
}
fseek(flag_file, 0L, REL_EOF); /* determine # lines in the file */
nlines=(int)ftell(flag_file)/width;
fprintf(stderr,"#lines in the file: %d\n",nlines);
rewind(flag_file);
if (ymax <= 0) {
ymax=nlines-start; /* default value of ymax */
}
if (ymax > nlines-start){
ymax = nlines-start;
fprintf(stderr,"insufficient #lines in the file, ymax: %d\n",ymax);
}
xw=xmax-xmin+1; /* width of each line to process */
yh=ymax-ymin+1; /* height of array */
offs=start+ymin-1; /* first line of file to start reading/writing */
fbf = (unsigned char *) malloc(sizeof(unsigned char)*width*yh);
if(fbf == (unsigned char *) NULL) {
fprintf(stderr,"failure to allocate space for flag array\n");
exit(-1) ;
}
gzw=(unsigned char **)malloc(sizeof(unsigned char*) * yh);
/**************** Read in flag data *********************/
fseek(flag_file, offs*width*sizeof(unsigned char), REL_BEGIN); /*seek start line */
fprintf(stdout,"reading input file...\n");
fread((char *)fbf, sizeof(unsigned char), yh*width, flag_file);
for (i=0; i< yh; i++){
gzw[i] = (unsigned char *)(fbf + i*width + xmin);
}
fprintf(stdout,"creating trees: width, height, mbl %d %d %d ...\n",xw, yh,mbl);
r_chrg=nearest_tree(gzw, yh, xw, mbl); /* grow the trees */
fprintf(stdout,"\nresidual charge: %d\n",r_chrg);
/************** write out flag array *************/
fprintf(stdout,"writing output flag file...\n");
fseek(flag_file, offs*width*sizeof(unsigned char), REL_BEGIN); /*seek start line */
fwrite((char *)fbf, sizeof(unsigned char), yh*width, flag_file);
fclose(flag_file);
return 0;
}
/* minimization of the longest connection in discharged trees */
/* 1992. Feb. 24. */
/* modified to include guiding centers and arbitrary dimensions 1993 Mar 23. */
/* by Paul Rosen */
/* search from right side to left */
/* charge_table :found in search from an unvisited charge */
/* n_charge: # of charges in table */
/* charge_t: pointer to the tree table */
/* charge_i,j: (x,y) of the charge */
#define size_charge_table 8000000
int n_charge,charge_t[size_charge_table];
int charge_i[size_charge_table],charge_j[size_charge_table];
/* tree_table */
/* n_tree: # of trees found */
/* tree_f: pointer to the charge found first */
/* tree_p: pointer to the charge of previous tree */
#define size_tree_table 3000000
int n_tree,tree_f[size_tree_table],tree_p[size_tree_table];
/* cut_table */
#define size_cut_table 8000000
int n_cut,cut_i[size_cut_table],cut_j[size_cut_table];
int dir_i[]={-1,1,0,1,1,0,-1,-1,0};
int dir_j[]={1,-1,1,1,0,0,0,-1,-1};
/* new_mode: flag decides if exisiting trees are used or not */
/* 0: unvisited charges are connected directly */
/* 1: charges are connected thru existing trees */
int new_mode=1;
#define size_search_table 5000
#define VISITED 0
#define GROUNDED 1
int n_search,si[size_search_table],sj[size_search_table];
/* generate a table of points "on" the size k box around (i1,j1) */
/* only available points are stored. */
void make_search_table(int ,int ,int, int, int) ;
void add_charge(unsigned char **, int, int) ;
void add_cut(unsigned char **,int, int) ;
int trace_tree(unsigned char **, int ,int ,int, int, int) ;
void connect_trees(unsigned char **, int) ;
int nearest_tree(unsigned char **, int, int, int) ;
void cutmap(unsigned char **, int, int, int, int) ;
void make_search_table(int i1,int j1,int k, int data_w, int data_h)
{
int i,j;
n_search=0;
if(k==0) return;
if((j1-k)>= -1)
for(i=i1-k;i<i1+k;i++)
if((i>= -1)&&(i<data_w)) {si[n_search]=i; sj[n_search++]=j1-k;}
if((i1+k)<data_w)
for(j=j1-k;j<j1+k;j++)
if((j>= -1)&&(j<data_h)) {si[n_search]=i1+k; sj[n_search++]=j;}
if((j1+k)<data_h)
for(i=i1+k;i>i1-k;i--)
if((i>= -1)&&(i<data_w)) {si[n_search]=i; sj[n_search++]=j1+k;}
if((i1-k)>= -1)
for(j=j1+k;j>j1-k;j--)
if((j>= -1)&&(j<data_h)) {si[n_search]=i1-k; sj[n_search++]=j;}
}
/* add charge (i,j) to the charge_table */
void add_charge(unsigned char **gzw, int i,int j)
{
if((gzw[i][j]&BRPT)!=0) return;
gzw[i][j] |= BRPT;
charge_i[n_charge]=i;
charge_j[n_charge]=j;
charge_t[n_charge++]=n_tree;
if(n_charge>=size_charge_table) {
fprintf(stderr,"error: subroutine add_charge, charge table is full!\n"); exit(1);}
}
/* add cut (i,j) to the cut_table */
void add_cut(unsigned char **gzw, int i,int j)
{
if((gzw[i][j]&TREE)!=0) return ;
/* {fprintf(stderr,"error: subroutine add_cut, there is a bug %d %d %d\n", gzw[i][j],i,j); return;} */
gzw[i][j] |= TREE;
cut_i[n_cut]=i;
cut_j[n_cut++]=j;
if(n_cut>=size_cut_table) {
fprintf(stderr,"error: subroutine add_cut, cut table is full!\n"); exit(1);}
}
/* tracing an existing tree */
/* (i,j) is position of the found visited charge. */
/* ip is a pointer to the charge in charge_table */
/* from which the visited charge was found. */
int trace_tree(unsigned char **gzw, int i,int j,int ip, int data_w, int data_h)
{
int i1,j1,i2,j2,k,nc,b;
/* create a new tree in tree_table */
tree_f[n_tree]=n_charge; /* pointer to the first found charge */
tree_p[n_tree]=ip; /* pointer to the charge in the previous tree*/
i1=i; j1=j; /* (i1,j1) is position of the first charge */
add_charge(gzw, i1,j1); /* Add the first charge to the charge_table */
/* Start tracing the tree */
b=0; /* b: flag indicates whether the connection */
/* to the boundary is found or not. */
/* 0: no connection to the boundary */
/* 1: connection was found */
n_cut=0; /* first no cuts are in the table */
/* Only 4 pixels around the first charge are inspected. */
for(k=2; k<6; k++) {
i2=i1+dir_i[k]; j2=j1+dir_j[k];
if((i2== -1)||(i2==data_w)||(j2== -1)||(j2==data_h))
/* The first charge was the next to the boundary. */
/* So the unvisited charge can be connected to the boundary */
/* using this visited charge. */
{b=1; goto clear_tree;}
if((gzw[i2][j2]&CUT)!=0) {
/* cuts found around the charge are added to the cut_table. */
add_cut(gzw,i2,j2);
/* if visited charges is on the cut, it is added to the */
/* charge_table. */
if((gzw[i2][j2]&VIST)!=0) add_charge(gzw,i2,j2);
}
}
/* search from found cuts */
nc=0; /* pointer to each cut in the cut_table */
while(nc<n_cut) { /* all of cuts in cut_table are inspected. */
i1=cut_i[nc]; /* (i1,j1) is inspected. */
j1=cut_j[nc++];
/* first, 3 pixels around the cut are checked. */
for(k=6; k<9; k++) {
i2=i1+dir_i[k]; j2=j1+dir_j[k];
if((i2== -1)||(i2==data_w)||(j2== -1)||(j2==data_h))
/* The cut was the next to the boundary, which means */
/* the visited charge (i,j) has a connection to the boundary, */
/* so the unvisited charge can be connected to the boundary */
/* thru this connection. */
{b=1; goto clear_tree;}
/* cuts checked found in a previous tree search are marked as TREE. */
if((gzw[i2][j2]&TREE)!=0) continue;
/* cuts and visited charges found are stored in tables. */
if((gzw[i2][j2]&CUT)!=0) add_cut(gzw,i2,j2);
if((gzw[i2][j2]&VIST)!=0) add_charge(gzw,i2,j2);
}
/* Second, 5 pixels around the cut are checked. */
for(k=0; k<5; k++) {
i2=i1+dir_i[k]; j2=j1+dir_j[k];
/* check connection to the boundary. */
if((i2== -1)||(i2==data_w)||(j2== -1)||(j2==data_h))
{b=1; goto clear_tree;}
/* check if it's already checked or not. */
if((gzw[i2][j2]&TREE)!=0) continue;
/* check if it's marked as 'CUT' or not. */
if((gzw[i2][j2]&CUT)!=0) {
/* add the found cut to cut_table. */
add_cut(gzw,i2,j2);
/* if visited charge is on the cut, it is added to charge_table. */
if((gzw[i2][j2]&VIST)!=0) add_charge(gzw,i2,j2);
}
}
}
/* end of search: TREE marks are all cleared. */
clear_tree:
for(k=0;k<n_cut;k++)
gzw[cut_i[k]][cut_j[k]] &= 255-TREE;
if(b==0) {
/* if the connection to the boundary was not found, */
/* the newly created tree is counted and */
/* VISITED is returned to calling procedure, which */
/* means the charge was connected to a floating tree. */
n_tree++;
if(n_tree>=size_tree_table) {
fprintf(stderr,"tree table is full\n"); exit(1);}
return VISITED;
} else
/* if the connection to the boundary was found, */
/* the newly created tree is canceled and */
/* GROUNDED is returned to calling procedure, which */
/* means the charge was connected to the boundary. */
return GROUNDED;
}
void connect_trees(unsigned char **gzw, int ip)
{
int t,i2,j2;
/* connect trees as a chain until the connection to the */
/* unvisited charge is established. */
while(ip!=0) {
t=charge_t[ip]; /* pointer to tree_table */
ip=tree_f[t];
i2=charge_i[ip]; /* (i2,j12) is the head of the tree. */
j2=charge_j[ip];
ip=tree_p[t]; /* ip: pointer to the charge in the previous tree */
/* connect the head of the tree to the previous tree */
cutmap(gzw, charge_i[ip],charge_j[ip],i2,j2);
}
}
/* Connect a pair of unvisited charges thru existing trees */
/* using a connection less than 'mbl'. If such a connection */
/* is impossible, leave the unvisited charges as they are. */
/* They will be connected later using larger 'mbl'. */
int nearest_tree(unsigned char **gzw, int data_w, int data_h, int mbl)
{
int i,j,i2,j2,ns;
int k,k_max;
int n_rest;
int ip,c;
n_rest=0;
for(j=0; j < data_h; j++) {
if (j%10 == 0){
fprintf(stdout,"\rprocessing column: %d",j);
fflush(stdout);
}
for(i=0; i < data_w; i++) {
if(((gzw[i][j]&CHG)==0)||((gzw[i][j]&VIST)!=0)) continue;
/* (i,j) is an unvisited charge.*/
gzw[i][j] |= BRPT; /* mark as BRPT */
/* initialize tree_table */
tree_f[0]=tree_p[0]=0; n_tree=1;
/* initialize charge_table */
charge_t[0]=0; charge_i[0]=i; charge_j[0]=j; n_charge=1;
c=CHG-(gzw[i][j]&CHG); /* c: opposite charge */
for(k_max=1; k_max <= mbl; k_max++) {
/* search from a charge in charge_table. */
/* charge_table contains the unvisited charge and charges */
/* found in search, and charges connected to them thru trees. */
for(ip=0; ip < n_charge; ip++) {
/* for each charge, pixels inside the size k_max box around it */
/* are checked from near to far. */
for(k=1; k <= k_max; k++) {
/* First all points on size k box around the charge are */
/* checked and stored in a table, */
/* then all points in the table are searched. */
make_search_table(charge_i[ip],charge_j[ip],k, data_w, data_h);
for(ns=0; ns < n_search; ns++) {
i2=si[ns]; j2=sj[ns];
if((i2 == -1)||(j2 == -1)||(i2 == data_w-1)||(j2 == data_h-1))
/* the charge is located at distance k from the boundary. */
goto case_BOUNDARY;
else if((gzw[i2][j2]&BRPT) != 0) continue;
else if(((gzw[i2][j2]&VIST) == 0)&&((gzw[i2][j2]&CHG) == c))
/* An unvisited charge with opposite charge is found. */
goto case_OPPOSITE;
else if((gzw[i2][j2]&(CHG+VIST)) || (gzw[i2][j2]&GUID))
/* When a visited charge or guiding center is found, */
/* if new_mode==1 then */
/* trace the existing tree from the charge and add */
/* charges connected to the tree to charge_table. */
/* When the traced tree has a connection to the */
/* boundary, the unvisited charge is connected to the */
/* charge(i2,j2). */
if(new_mode!=1) continue;
else if(trace_tree(gzw,i2,j2,ip,data_w,data_h)==GROUNDED) goto case_GROUNDED;
}
}
}
}
n_rest++; /* count unvisited charges which are not discharged. */
goto clear_BRPT;
case_OPPOSITE:
/* mark the found unvisited charge. */
gzw[i2][j2] |= VIST;
case_BOUNDARY:
case_GROUNDED:
/* mark the unvisited charge.*/
gzw[i][j] |= VIST;
/* connect charges and trees chainly. */
cutmap(gzw, charge_i[ip],charge_j[ip],i2,j2);
connect_trees(gzw, ip);
clear_BRPT:
for(ip=0; ip<n_charge; ip++) gzw[charge_i[ip]][charge_j[ip]] &= 255-BRPT;
}
}
return n_rest;
}
void cutmap(unsigned char **gzw, int i1,int j1,int i2,int j2)
{
int m,ki,kj,kk;
int ii,ji;
ki=(i1<i2 ? i2-i1 : i1-i2);
kj=(j1<j2 ? j2-j1 : j1-j2);
kk=(ki<kj ? kj : ki);
if(kk==0) {fprintf(stderr,"error: subroutine cutmap! kk=0\n"); return;}
for(m=1; m<=kk; m++) {
ii=i1+(i2-i1)*m/kk;
ji=j1+(j2-j1)*m/kk;
if(j1-j2==kk) ji++;
if(i1-i2==kk) ii++;
if(ii<0) ii=0;
if(ji<0) ji=0;
if((gzw[ii][ji]&CUT)==0)
gzw[ii][ji] |= CUT;
}
}