#Original Function Location: /themis/lib/dav_lib/public_library/latest/general_science.dvrc /themis/lib/dav_lib/library/general_science.dvrc Source Code for Function: "ktoc()" in "general_science.dvrc" (Public)

general_science_version=1.02

# ctok       - taken from /themis/lib/themis_dvrca
# ktoc       - taken from /themis/lib/themis_dvrca
# ftoc       - taken from /themis/lib/themis_dvrca
# ctof       - taken from /themis/lib/themis_dvrca
# ftok       - taken from /themis/lib/themis_dvrca
# ktof       - taken from /themis/lib/themis_dvrca
# eigen2     - taken from /u/bandfield/josh.dvrc
# pca_byte        - taken from /u/gorelick/pca.dv
# pca        - c.edwards 2-9-2011
# pca2       - taken from /u/bandfield/josh.dvrc, formerly called jpca()
# pca2_recon - taken from /u/cedwards/christopher.dvrc
# round      - taken from /u/knowicki/dvrc/tools.dvrc
# scalebar   - taken from /u/cedwards/christopher.dvrc
# add_grid      - created 1-32-2008 - replaces old add_grid


#moved pca to pca_byte and created a new pca that works for N band data 
#pca should retain a similar usage to the old pca (but not output byte data) - c.edwards 2-09-11

define ctok(0,1) {
  if ($ARGC == 0) return(0)
  a = $1 + 273.15
  return(a)
}

define ktoc(0,1) {
  if ($ARGC == 0) return(0)
  a = $1 - 273.15
  return(a)
}

define ftoc(0,1) {
  if ($ARGC == 0) return(0)
  a = ($1 - 32) * 5./9.
  return(a)
}

define ctof(0,1) {
  if ($ARGC == 0) return(0)
  a = $1 * 9./5. + 32
  return(a)
}

define ftok(0,1) {
  if ($ARGC == 0) return(0)
    a = ctok(ftoc($1))
    return(a)
}

define ktof(0,1) {
  if ($ARGC == 0) return(0)
    a = ctof(ktoc($1))
    return(a)
}







define eigen2() {


if ($ARGC == 0) {
printf("The pure, undiluted joy of factor analysis.\n")
printf("Compute eigenvalues and vectors from a set of spectra\n")
printf(" \n")
printf("$1 = Input array or vectors\n")
printf("$2 = Number of components\n")
printf("$3 = Optional: Number of iterations. \n")
printf(" \n")

return(0)
}
# Transform input array into m x n x 1 array. n is number of spectra.

data=$1
neigen=$2
iterate=200

if ($ARGC ==3) {

iterate=$3

}

if (dim(data)[3,,] !=1) {

# Take strips off the cube and reassemble into a 2 dimensional matrix

Dat=translate(data[,1,],from=x, to=y)
Dat=translate(Dat, from=z, to=x)

for (i=2; i<=(dim(data)[2,,]); i+=1) {

    Dat_temp=translate(data[,i,],from=x, to=y)
    Dat_temp=translate(Dat_temp,from=z, to=x)
    Dat=cat(Dat,Dat_temp,y)
}
}

if (dim(data)[3,,] ==1) {    

Dat=data
}
# Double C[$2]
# Double Dat[nvecs($1)]
# Double eigenvalues[$2]
# Double evecs[($2+1)]

average=avg(Dat,axis=y,ignore=0)

Dat=Dat-average
Dt=translate(Dat,from=x,to=y)
Z=mxm(Dat,Dt)

# Double Ctp[npts(Dt[1])]

printf("\n")
printf("EV#  Iterat.  Eigenvalue\n")
printf("---+--------+-----------\n")

C=create(x=dim(Z)[1,,],y=neigen,z=1,start=0,step=0,format=float)
eigenvalues=create(x=neigen,y=1,z=1,start=0,step=0,format=float)

for (i=1; i<=neigen; i+=1) {

    Ctp=clone(0.57735,y=dim(Dt)[1,,])

    eigen_cnt=1
    check=1

    while ((eigen_cnt < iterate) && (check > 0.000000001)) {

        Cnew=mxm(Z,Ctp)
        Eval=sum(Cnew^2)^0.5
        Cnew=Cnew/Eval
        Ctp=Cnew

        # Check Zc=yc

        Zc=mxm(Z,Cnew)
        yc=translate(Eval*Cnew,from=x,to=y)
        check=sum((translate(yc,from=x,to=y)-Zc)^2)^.5

        if (check > 0) {
            check=check/(1/(sum(Zc^2)^.5))
        }
        eigen_cnt=eigen_cnt+1
    }

    C[,i]=translate(Cnew,from=x,to=y)
    eigenvalues[i]=Eval


    # Calculate residual Matrix

    Z=Z-(mxm((Eval*Cnew),translate(Cnew,from=x,to=y)))


    printf("%.0f      ",(i))
    printf("%.0f      ",(eigen_cnt))
    printf("%.6f\n",Eval)

    }

    printf("\n")

    # Calculate R matrix eigenvectors

    evecs=translate(mxm(Dt,translate(C,from=x,to=y)),from=x,to=y)

    out=struct(evecs,evals,avg,C)

    out.evecs=evecs
    out.evals=eigenvalues
    out.avg=average
    out.C=C
    return(out)
}



define pca(ignore,struct) {
    if ($ARGC != 1) {
                printf("Do a Princple Component Analysis of an N band real data image\n\n")
        printf("usage: pca(input_image [,ignore=FLOAT][, struct=BOOL])\n")
                printf("ignore = black space value (no default)\n")
                printf("struct = return the structure with evecs/evals/covar (default is 0)\n\n") 
                printf("For the three band stretched version use the pca_byte function\n\n")
                printf("NOTE: for the old 3 band pca version see the pca_byte function.\n")
                printf("This version replaced the old byte version on 2-9-2011\n\n")
                printf("c.edwards 2-9-2011\n")
        return(0);
    }

    # compute the symmetric covariance matrix and eigenvectors of it.
    data = $1

    if (HasValue(ignore)) {
        c = covar(data, axis=z, ignore=ignore)
    } else {
        c = covar(data, axis=z)
    }

    e = eigen(c)
        evals = e[1]
    evecs = e[2:]

    dim = dim(data);
    data = bip(data)
    resize(data, dim[3], dim[1]*dim[2]);

    if (HasValue(ignore)) {
        avg = avg(data,y,ignore=ignore)
    } else {
        avg = avg(data,y)
    }

    pc = mxm(data-avg, evecs);
    pc = bip(pc)

    # reshape the data back to it's original size
    resize(pc, dim[1], dim[2], dim[3]);
    resize(data, dim[1], dim[2], dim[3]);

    if (HasValue(ignore)) {
        pc[where data == ignore] = ignore
    }

        if(HasValue(struct)==1) {
        return({evecs=translate(evecs,y,y,flip=1),evals=translate(evals,y,y,flip=1),covar=translate(c,y,y,flip=1),data=translate(pc,z,z,flip=1)})
        } else {
            return(translate(pc,z,z,flip=1))
        }
}



#
# principle component analysis, optmized for 3-band BYTE images
# Data will be centered around 127, with a sigma of +/- 50.
#


define pca_byte() {
    if ($ARGC != 1) {
                printf("Do a Princple Component Analysis of a 3 band byte image\n\n")
        printf("usage: pca(input_image)\n")
        return(0);
    }

    # compute the symmetric covariance matrix and eigenvectors of it.
    a = $1
    c = covar(a, axis=z)
    e = eigen(c)

    # generate the scaling matrix with the scaling factors on the diagonal
    # and compute the rotation matrix
    s = identity(3) * 50.0/sqrt(e[1])
    m = mxm(mxm(e[2:], s), translate(e[2:], x, y))

    # We have to reshape the data to push it through mxm() because mxm is dumb.
    # Force the input to be bip so we can use the forbidden resize() function.
    d = dim(a);
    a = bip(a)
    resize(a, 3, dim(a)[1]*dim(a)[2]);

    # subtract the mean of each band, rotate and add back 127
    a = a - avg(a,y);
    a = mxm(a, m);
    a = a + 127;
    a = byte(bip(a));

    # reshape the data back to it's original size
    resize(a, d[1], d[2], d[3]);
    return(a)
}




define pca2() {

if ($ARGC == 0) {
    printf("Get concentration images for each eigenvector.\n")
    printf(" \n")
    printf("$1 = radiance image (same bands as eigen2 output)\n")
    printf("$2 = output structure from eigen2\n")    
    printf(" \n")
    printf(" \n")
    return(0)
}

eigen=$2
image=$1

# Invert the Matrix.

evecs=translate(eigen.evecs,from=x,to=y)
evecsT=eigen.evecs

sq=mxm(evecsT,evecs)
sq=minvert(sq)
sq_end=mxm(evecs,sq)

# Subtract the mean from eigen2 from the image.

image=image-translate(eigen.avg,from=x,to=z)

# Disassemble the image to shove it through mxm

dimage = dim(image)
image = bip(image)
resize(image, dimage[3], dimage[1]*dimage[2])

# Get concentrations

conc=mxm(image,sq_end)

# Get the image format back

conc=bip(conc)
resize(conc,dimage[1],dimage[2],dim(conc)[1])

return(conc)
}




define pca2_recon() {
  
  if($ARGC<3) {
    printf("\nRecombine a THEMIS IR image after jpca()\n\n")
    printf("$1=The principal components array, output of jpca()\n")
    printf("$2=The eigen2() structure, output of eigen2()\n")
    printf("$3=The number of eigen vectors to use\n")
    printf("\nc.edwards 4/2/04\n\n")
    return(null)
  }

  pca=$1
  eigen=$2
  iter=$3
  xdim=dim(pca)[1]
  ydim=dim(pca)[2]
  zdim=dim(pca)[3]

# error handeling
  if(zdim     printf("\nYou only have %i principal components\n",zdim)
    printf("You can't reconstruct %i components...DUH\n\n",iter)
    return(null)
  }

# set up image for reconstruction
  image=clone(0.0,xdim,ydim,1)
  
  printf("\n  -------------\n")
  printf("  | Component |\n")
  printf("  |-----------|\n")

# loop through and reconstruct data using eigen vectors
  for(i=1;i<=iter;i+=1) {
    printf("  |     %i     |\n",i)
    image=image+pca[,,i]*clone(translate(eigen.evecs[,i],from=x,to=z),x=xdim,y=ydim)
  }
  
# add the average of the data
  printf("  |  Add Avg. |\n")
  image=image+translate(eigen.avg,from=x,to=z)
  printf("  -------------\n\n") 

  return(float(image))
}






define round() {
  # rounds the input to the nearest whole number

  floatnums = $1

  wholenums = float(int(floatnums))

  remainder = floatnums-wholenums
  remainder[where remainder >= 0.50] = 1.0
  remainder[where remainder < 0.50 && remainder > -0.5] = 0.0
  remainder[where remainder <= -0.5] = -1.0

  wholenums = wholenums+remainder
  return(int(wholenums))
}



define scalebar(xpos,ypos,xsize,ysize,font,ignore,sample,mintext,minscale,maxtext,maxscale,scaleonly,direction,justify) {

  if($ARGC==0) {
    printf("Add a scale bar to a numerical array\n\n")
    printf("Syntax: scalebar(data [,xpos=INT] [,ypos=INT] [,xsize=VAL] [,ysize=VAL] [,font=STRING]\n")
    printf("                 [,ignore=VAL] [,sample=VAL] [,mintext=STRING] [,maxtext=STRING]\n")
    printf("                 [,scaleonly=STRING] [,direction=STRING] [,justify=STRING])\n")
    printf("data = numerical array of any size, with or without ignore values\n")
    printf("direction = direction of the scale bar (Default = \"vertical\")\n")
    printf("ignore = ignore value of the data (Default = -32768)\n")
    printf("scaleonly = Return only the scale bar with the endpoint values shown (Default = \"no\")\n")
    printf("justfiy = justification of the scale bar (Default = \"top,right\")\n")
    printf("justifications include: \"top\", \"middle\", \"bottom\", \"left\", \"center\", \"right\"\n")
    printf("xsize = the size of the scale bar in the x direction as a fraction \n        of the numerical array dimension (Default = 30 (=1/30))\n")
    printf("ysize = the size of the scale bar in the y direction as a fraction \n        of the numerical array dimension (Default = 10 (=1/10))\n")
    printf("mintext = User defined text for minimum value (max 15 characters)\n") 
    printf("minscale = User defined minimum value\n") 
    printf("maxtext = User defined text for minimum value (max 15 characters)\n") 
    printf("maxscale = User defined maximum value\n") 
    printf("sample = use a sample array to add the scale bar to $1\n")
    printf("font = the font used to display min and max values on scale bar (Default = \"helvetica\")\n")
    printf("xpos = x positon of the top right of the scale bar (Default = 10) \n")
    printf("ypos = y position of the top right corner of the scale bar (Default = 10) \n\n")
    printf("NOTE:  This script requires that convert (ImageMagick) is installed and is defined in your path\n")
    printf("\nc.edwards 8/12/06\n\n")
    return(null)
  }

  verbose=0

  f="helvetica"
  x=10
  y=10
  xf=30
  yf=10
  ign=short(-32768)
  dir="vertical"

  if(HasValue(font)) f=font
  if(HasValue(xpos)) x=xpos
  if(HasValue(ypos)) y=ypos
  if(HasValue(xsize)) xf=xsize
  if(HasValue(ysize)) yf=ysize
  if(HasValue(ignore)) ign=ignore
  if(HasValue(sample)) data=sample
  if(HasValue(direction)) dir=direction
  if(HasValue(sample)==0) data=$1
  if(dir=="vertical") {
    if(HasValue(xsize)) yf=xsize
    if(HasValue(ysize)) xf=ysize
  } 
  if(HasValue(justfiy)) just=justify
  if(HasValue(justify) && (HasValue(ypos) || HasValue(xpos))) {
    printf("Please choose either a justitfication or an x,y pair\n")
    return(null)
  } 
  
  # set up variable and get the min, max and dimensions
  dimdata=dim(data)
  min=min(data,ignore=ign)
  max=maxval=max(data,ignore=ign)

    if(HasValue(maxscale)) max=maxval=maxscale
    if(HasValue(minscale)) min=minscale

  #create the scale
  scale=clone(create(1,int(dimdata[1]/xf),1,start=min,step=(float(max-min))/(dimdata[1]/xf),format=format(data)),x=int(dimdata[2]/yf))

  #get the dimensions of the scale and buffer the edge by 1 ignore pixel
  scaledim=dim(scale)
  scale[1]=ign
  scale[scaledim[1]]=ign
  scale[,1]=ign
  scale[,scaledim[2]]=ign
 
  #flip if horizontal
  if(dir=="horizontal") scale=translate(scale,x,y)

  #check for user defined text
  if(HasValue(mintext)) min=mintext
  if(HasValue(maxtext)) max=maxtext

  #make the temporary picture for the text
  write(byte(clone(0,1000,100,1)),$TMPDIR+"/text.png",png,force=1)
  syscall("convert -font "+f+" -fill white -pointsize 120 -draw 'text 0,90 \""+min+"\"' "+$TMPDIR+"/text.png "+$TMPDIR+"/mintext.png")
  syscall("convert -font "+f+" -fill white -pointsize 120 -draw 'text 0,90 \""+max+"\"' "+$TMPDIR+"/text.png "+$TMPDIR+"/maxtext.png")
 
  # read in tmp files and calculate the maximum x dimension
  mintext=read($TMPDIR+"/mintext.png",record=1)
  maxtext=read($TMPDIR+"/maxtext.png",record=1)
  pos=int(max(cat(int(max(rightline(mintext,ignore=0))),int(max(rightline(maxtext,ignore=0))),x)))+5
 
  #write another round of temporary files to resize the two images
  write(mintext[:pos],$TMPDIR+"/mintext2.png",png,force=1)
  write(maxtext[:pos],$TMPDIR+"/maxtext2.png",png,force=1)

  #resize the files to the size of the scale bar
  if(dir=="horizontal") {
    syscall("convert -geometry x"+scaledim[1]/2+" "+$TMPDIR+"/mintext2.png "+$TMPDIR+"/mintext3.png")
    syscall("convert -geometry x"+scaledim[1]/2+" "+$TMPDIR+"/maxtext2.png "+$TMPDIR+"/maxtext3.png")

    #read the files back in 
    tmp1=format(read($TMPDIR+"/mintext3.png",record=1),format=format(data))
    tmp2=format(read($TMPDIR+"/maxtext3.png",record=1),format=format(data))

    #shrink the text by 1/2 so it doesn't look ridiculous
    mintext=maxtext=clone(format(0,format=format(data)),dim(tmp1)[1],scaledim[1],1)
    j=2
    if(scaledim[1]*3/4-1-scaledim[1]/4 != dim(tmp1)[2]) j=1
    mintext[,scaledim[1]/4:scaledim[1]*3/4-j]=tmp1
    maxtext[,scaledim[1]/4:scaledim[1]*3/4-j]=tmp2
    tmp1=tmp2=0
  }
  
  if(dir=="vertical") {
    #read files back in
    syscall("convert -geometry "+scaledim[1]+"x "+$TMPDIR+"/mintext2.png "+$TMPDIR+"/mintext3.png")
    syscall("convert -geometry "+scaledim[1]+"x "+$TMPDIR+"/maxtext2.png "+$TMPDIR+"/maxtext3.png")
   
    #read the files back in 
    mintext=format(read($TMPDIR+"/mintext3.png",record=1),format=format(data))
    maxtext=format(read($TMPDIR+"/maxtext3.png",record=1),format=format(data))
  }   

  #change text values to match the data
  mintext[where mintext==0]=ign
  maxtext[where maxtext==0]=ign  
  mintext[where mintext!=ign]=maxval
  maxtext[where maxtext!=ign]=maxval

  #return scale if only scale is wanted and cat together the bar and text
  verbose=1
  if(dir=="horizontal") {
     scale=cat(bsq(mintext),scale,bsq(maxtext),axis=x)
     if(HasValue(scaleonly)) return(scale)
  }
  if(dir=="vertical") {
    scale=cat(bsq(mintext),scale,bsq(maxtext),axis=y)
    if(HasValue(scaleonly)) return(scale)
  }

  #fill in point specified by user
  if(HasValue(sample)) data=$1
  scaledim=dim(scale)
  datadim=dim(data)
  #check for justification and parse the options
  if(HasValue(justify)) {
    commapos=strstr(justify,",")
    vert=justify[:commapos-1]
    if(vert!="top" && vert!="bottom" && vert!="middle") { 
      printf("You can only choose top, middle or bottom for vertical justification\n")
      return(null)
    }
    if(vert=="top") y=10
    if(vert=="bottom") y=datadim[2]-10-scaledim[2]
    if(vert=="middle") y=datadim[2]/2-scaledim[2]/2
    horiz=justify[commapos+1:]
    if(horiz!="right" && horiz!="left" && horiz!="center") { 
      printf("You can only choose right, left or center for horizontal justification\n")
      return(null)
    }
    if(horiz=="left") x=10
    if(horiz=="right") x=datadim[1]-10-scaledim[1]
    if(horiz=="center") x=datadim[1]/2-scaledim[1]/2
  }

  #fill in and return data
  data[x:scaledim[1]+x-1,y:scaledim[2]+y-1]=scale
  return(data)
}




define add_grid(xo,yo,thick) {
  if ($ARGC <4) {
    printf ("\n add grid to image \n")
    printf (" usage: add_grid(input, dx, dy, line_color [,xoffset] [,yoffset] [,thickness])\n")
    printf (" example:  b = add_grid(a, 48, 48, 'halfwhite', xo=8, yo=4,thick=2)  \n\n")

       return(null)
  }

    data=$1
    dx=$2
    dy=$3
    
    if(HasValue(thick)==0) thick=0
    if(HasValue(xo)==0)xo=dx
    if(HasValue(yo)==0)yo=dy

    mask=byte(data*0)[,,1]

    for(i=xo;i<=dim(data)[1];i+=dx){
        if(i-thick>=1 && i+thick<=dim(data)[1]-thick)    mask[i-thick:i]=255
        if(i+thick<=dim(data)[1]-thick)    mask[i:i+thick]=255
    }
    for(i=yo;i<=dim(data)[2];i+=dy) {
        if(i-thick>=1 && i+thick<=dim(data)[2]-thick)    mask[,i-thick:i]=255
        if(i+thick<=dim(data)[2]-thick)    mask[,i:i+thick]=255
    }

    if ($4 == "white") {
        data = data+mask
    } else if ($4 == "black") {
        data = data-mask
    } else if ($4 == "quarterwhite") {
        data = data+byte(0.25*mask)
    } else if ($4 == "quarterblack") {
        data = data-byte(0.25*mask)
    } else if ($4 == "halfwhite") {
       data = data+byte(0.50*mask)
    } else if ($4 == "halfblack") {
       data = data-byte(0.50*mask)
    }

    return(data)

}