#Original Function Location: /themis/lib/dav_lib/library/map_projection.dvrc Source Code for Function: "latlonDMS2dec()" in "map_projection.dvrc" (Beta)

map_projection_version=1.08

#1.00 initial version. added jmars function
#    this allows a user to create a link between jmars and davinci
#1.01 added read_geometa, read_geo, write_geotiff
#1.02 updated read_geometa, read_geo, write_geotiff and added proj_geo
#1.03 updated read_geo, read_geometa, write_geotiff, proj_geo to support
# assigning a source projection, selecting a subdataset extracting and adding gcps
# also added function add_gcps_geo
#1.04 added read_geoshape,write_geoshape,coordproj_geo,proj_geoshape,
# shape2raster_geo, find_proj, get_proj
# and fixes to other geo functions
#1.06 added write_envi function
#1.08 added support for gdal 3.0

# jmars                        -created by c.edwards 2-7-2011
# read_geometa     -created by c.edawrds 4-9-2013
# read_geo         -created by c.edawrds 4-9-2013
# write_geotiff    -created by c.edawrds 4-9-2013
# proj_geo         -created by c.edwards 4-10-2013
# add_gcps_geo     -created by c.edwards 4-24-2013
# find_proj        -created by c.edwards 5-12-2013
# get_proj         -created by c.edwards 5-12-2013
# read_geoshape    -created by c.edwards 5-12-2013
# write_geoshape   -created by c.edwards 5-12-2013
# proj_geoshape    -created by c.edwards 5-12-2013
# proj_geocoord    -created by c.edwards 5-12-2013
# shape2raster_geo -created by c.edwards 5-12-2013
# gdal_version     -created by c.edwards 5-12-2013
# write_envi             -created by c.edwards 10-9-2014


define jmars(id,ul,ur,ll,lr,ignore,name,port,host,v,tmpdir,geo) {

    if($ARGC<1) {
        printf("Use this function to output a data file to your JMARS Session\n")
        printf("JMARS will take the input data and project it on to the current map in the Davinci Stamps layer\n\n")
        printf("Required:\n")
        printf("\t$1 = stretched byte data or a file path\n")
        printf("\tul = Latitude//Longitude of the upper left corner of the data\n")
        printf("\tlr = Latitude//Longitude of the lower right corner of the data\n")
        printf("\tNote: if only ul and lr are specified ur and ll values will be filled in automatically\n")
        printf("\tur = Latitude//Longitude of the upper right corner of the data\n")
        printf("\tll = Latitude//Longitude of the lower left corner of the data\n\n")
        printf("OR\n")
        printf("\t$1 = a STRUCT with a stretched byte .data, .ul, .lr, (optional, .ur, .ll) elements in the formats above\n\n")
        printf("\t$1 = stretched byte data or a file path\n")
        printf("\t$2 = an ISIS2 or ISIS3 structure (from load_pds) with map projection information\n\n")
        printf("Optional:\n")
        printf("\thost = name of the machine the instance of JMARS is running on (Default=\"localhost\")\n")
        printf("\tport = port number specified in the Davinci Stamps Layer (Default=56277)\n")
        printf("\tignore = ignore value for image null space (Default = 0)\n")
        printf("\tname = specifiy a custom dataset name (Default = \"DV Upload \"+ID#\n")
        printf("\tid = specify an id for JMARS to identify this dataset\n")
    printf("\t\t this will auto increment by default, but can be forced to overwrite \n")
        printf("\ttmpdir = specify an alternate temporary directory (must exist)\n")
    printf("\tgeo = re-project the input GeoStruct to the JMARS projection (Default = 0)\n")
        printf("c.edwards 9/8/10\n")
        return(null)
    }

    if(HasValue(tmpdir)==0) {
        tmpdir=$TMPDIR
    }

    if(HasValue(ignore)==0) {
        ignore="0"
    } else { 
        igndim=dim(ignore)
        ignore=resize(ignore,igndim[1]*igndim[2]*igndim[3],1,1)
        ignstr=sprintf("%d",ignore[1])
        for(i=2;i<=dim(ignore)[1];i+=1) {
            ignstr=sprintf("%s,%d",ignstr,ignore[i])
        }
        ignore=ignstr
    }

    if(HasValue(geo)==0) geo=0
    if(HasValue(v)) printf("Ignore value string is: %s\n",ignore)


    if(HasValue(id)==0) {
        if(fexists(tmpdir+"/000001_dvjmars.png")) {
            previous=syscall("ls "+tmpdir+"/??????_dvjmars.png")
            id=atoi(basename(previous)[:6,length(previous)])+1
        } else {
            id=1
        }
    }

    if(HasValue(v)) printf("id=%i\n",id)

    if(HasValue(name)==0) name=sprintf("DV Upload %.6d",id)
    if(HasValue(port)==0) port=56277
    if(HasValue(host)==0) host="localhost"

    if(HasValue(v)) {
        printf("name=%s\n",name)
        printf("host=%s\n",host)
        printf("port=%i\n",port)
    }

    outfile=sprintf("%s/%.6d_dvjmars.png",tmpdir,id)
    urlprefix=sprintf("http://%s:%i/jmarsdvlink?",host,port)

    ver=version()[18:]
    ver="davinci "+ver

    #check for the data with specified ul, lr etc 
    if(type($1)!="STRUCT" && $ARGC==1) { 
        if(HasValue(v)) printf("User defined coords case\n")

        if(HasValue(ul)==0) {
            printf("Upper Left Lat//Lon are required\n")
            return(null)
        }
        if(HasValue(lr)==0) {
            printf("Lower Right Lat//Lon are required\n")
            return(null)
        }
        if(HasValue(ll)==0) {
            printf("Using set Upper Left Longitude and Lower Right Latitude bounds for the Lower Left corner\n")
            ll=lr[1]//ul[2]
        }
        if(HasValue(ur)==0) {
            printf("Using set Upper Left Latitude and Lower Right Longitude bounds for the Upper Right corner\n")
            ur=ul[1]//lr[2]
        }

    }    

    if ($ARGC==2) {
        if(type($2)=="STRUCT" || type($2)=="STRING") {

            if(type($2)=="STRING") {
                if(HasValue(v)) printf("Trying to load pds file\n")
                struct=load_pds($2,data=0)
            } else {
                if(HasValue(v)) printf("We have a pds struct\n")
                struct=$2
            }
            
            if(HasValue(get_struct(struct,"IsisCube"))) {
                #we think we have the isis3 case            
                if(HasValue(v)) printf("ISIS 3 case\n")

                if(HasValue(get_struct(struct.IsisCube,"Mapping"))) {
                    minlat=float(struct.IsisCube.Mapping.MinimumLatitude)
                    maxlat=float(struct.IsisCube.Mapping.MaximumLatitude)
                    westlon=float(struct.IsisCube.Mapping.MinimumLongitude)
                    eastlon=float(struct.IsisCube.Mapping.MaximumLongitude)
                }
                #just because we don't quite trust the isis label to always be min/max
                minlon=min(westlon//eastlon)
                maxlon=max(westlon//eastlon)

                #parse it to the jmars way...            
                ul=maxlat//minlon
                ur=maxlat//maxlon
                ll=minlat//minlon
                lr=minlat//maxlon

            } else if(HasValue(get_struct(struct,"qube"))){
                #we think we ahve the isis2 case
                if(HasValue(v)) printf("ISIS 2 case\n")

                if(HasValue(get_struct(struct.qube,"image_map_projection"))) {
                    minlat=float(struct.qube.image_map_projection.minimum_latitude)
                    maxlat=float(struct.qube.image_map_projection.maximum_latitude)
                    westlon=float(struct.qube.image_map_projection.westernmost_longitude)
                    eastlon=float(struct.qube.image_map_projection.easternmost_longitude)
                }

                #just because we don't quite trust the isis label to always be min/max
                minlon=min(westlon//eastlon)
                maxlon=max(westlon//eastlon)

                #parse it to the jmars way...            
                ul=maxlat//minlon
                ur=maxlat//maxlon
                ll=minlat//minlon
                lr=minlat//maxlon

            } else {
                if(HasValue(get_struct(struct,"ul"))) {    
                    ul=struct.ul
                }
                if(HasValue(get_struct(struct,"lr"))) {    
                    lr=struct.lr
                }
                if(HasValue(get_struct(struct,"ll"))) {    
                    ll=struct.ll
                } else {
                    ll=lr[1]//ul[2]
                }
                if(HasValue(get_struct(struct,"ur"))) {    
                    ur=struct.ur
                } else {
                    ur=ul[1]//lr[2]
                }
            } 
        }
    }

    #check for the structure case where we may have .data, .lr, .ul
    if(type($1)=="STRUCT" && $ARGC==1) {

        if(HasValue(v)) printf("User defined struct case\n")

        struct=$1

        #this will blow up if we don't have a geo struct....
        if(geo==1) {
            struct=proj_geo(struct,"+proj=eqc +lat_ts=0 +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +a=3396190 +b=3396190 +units=m +no_defs")
        }

        if(HasValue(get_struct(struct,"data")) || HasValue(get_struct(struct,"image"))) {
            if(HasValue(get_struct(struct,"ul")) && HasValue(get_struct(struct,"lr"))) {
                ul=get_struct(struct,"ul")
                lr=get_struct(struct,"lr")
                
                if(HasValue(get_struct(struct,"ur"))) {
                    ur=get_struct(struct,"ur")
                } else {
                    ur=ul[1]//lr[2]
                }
                if(HasValue(get_struct(struct,"ll"))) {
                    ll=get_struct(struct,"ll")
                } else {
                    ll=lr[1]//ul[2]
                }
            } else {
                printf("Lat//Lon values are required for each corner\n")
                return(null)
            }

            if(HasValue(get_struct(struct,"data"))) {
                data=get_struct(struct,"data")
            } else if (HasValue(get_struct(struct,"image"))) {
                data=get_struct(struct,"image")
            }

            if(type(data)=="byte") {
                if(HasValue(v)) printf("Writing out .data from struct to  file\n")
                if(dim(data)[3]!=1 && dim(data)[3]!=3) {
                    printf("Data must have only 1 or 3 bands\n")
                    return(null)
                } else { 
                    write(data,outfile,png,force=1)
                }
            } else {
                printf("Error only byte data may be used with JMARS at this time\n\n")
                return(null)
            }
        }

    #this is a check to just copy the file to the location (if it is on disk somewhere...)
    #this is probably dangerous since it is most likely not a png file
    } else if(type($1)=="STRING") {
        data=read($1)
        if(dim(data)[3]!=1 && dim(data)[3]!=3) {
            printf("Data must have only 1 or 3 bands\n")
            return(null)
        } else { 
            write(data,outfile,png,force=1)
        }
        
        #this is probably dangerous since it is most likely not a png file
        #copy($1,outfile)

    #this is the case where we have data as a pds structure or with user defined points 
    } else if(type($1)=="byte") {    
        if(HasValue(v)) printf("Writting out unstretched data to file\n")
            if(dim($1)[3]!=1 && dim($1)[3]!=3) {
                printf("Data must have only 1 or 3 bands\n")
                return(null)
            } else { 
                write($1,outfile,png,force=1)
            }
    #this is the case where we have unstretched data as a pds structure or with user defined points
    } else if(type($1)=="float" || type($1)=="short" || type($1)=="int" || type($1)=="double") {
        printf("Error only byte data may be used with JMARS at this time\n\n")
        return(null)
    } else {
        printf("No valid data was found\n")
        return(null)
    }
    
    ulstr=sprintf("&ullat=%f&ullon=%f",ul[1],ul[2])
    urstr=sprintf("&urlat=%f&urlon=%f",ur[1],ur[2])
    llstr=sprintf("&lllat=%f&lllon=%f",ll[1],ll[2])
    lrstr=sprintf("&lrlat=%f&lrlon=%f",lr[1],lr[2])

    url=sprintf("%spath=%s%s%s%s%s&ignore=%s&id=%.6d&name=%s&version=%s",urlprefix,outfile,ulstr,urstr,llstr,lrstr,ignore,id,name,ver)

    verbose=0
    if(HasValue(v))    {
        printf("%s\n",url)
        verbose=3
    }

    success=read_lines(url)
    verbose=3

    if(HasValue(success)) {
        success=atoi(success[,1])
        if(success==1) {
            printf("Your data is now available in: \n\tJMARS Session:\t\"%i\"\n\tData ID:\t\"%.6d\"\n\tData Name:\t\"%s\"\n",success,id,name)
        } else {
            printf("ERROR:Your data is NOT available in JMARS\n")
        }
    } else {
        printf("ERROR:Your data is NOT available in JMARS\n")
    }
    return(success)
}



define read_geometa(raw,opts,v) {

    #print the help
    if($ARGC<1) {
        printf("\nThis function reads the metadata from a Geo-Aware file\n")
        printf("The input data must be a format gdal understands\n\n")
        printf("$1=filename\n\n")
        printf("Options:\n")
        printf("\topts=optional gdalinfo arguments (default=\"\")\n\n")
        printf("\traw=return the raw gdalinfo file (Default=0)\n")
        printf("Returns a standard davinci Geo-Struct\n")
        printf("\n")
        printf("NOTE: This function requires $DV_GDAL_PATH\n")
        printf("and gdal version >=2.0 and >=3.0\n\n")
        printf("c.edwards 4/9/13\n")
        return(null)
    }    

    verbose=0
    #set up the defaults
    if(HasValue(raw)==0) raw=0
    if(HasValue(opts)==0) opts=""
     if(HasValue(v)==0) v=0
    proj=0

    #grab the filename and run gdalinfo
    filename=$1

    #handle the remote case
    remote=0
    prefix=cat("http://","https://","ftp://","sftp://","file:///",axis=y)
    for(i=1;i<=length(prefix);i+=1) {
        if(filename[:length(prefix[,i])]==prefix[,i]) {
            remote=1
        }
    }
    
    if(remote==1) {
        newfile=$TMPDIR+"/"+basename(filename)+".copy"
        filename=copy(filename,newfile,force=1)
    }

    version=gdal_version(value=1)
    if(version<2 && version>1) {
        wkt_file=syscall($DV_GDAL_PATH+"/gdalinfo -norat "+opts+" "+filename)
    } else if (version>=2 && version<3) {
        wkt_file=syscall($DV_GDAL_PATH+"/gdalinfo  -proj4 "+opts+" "+filename)
    } else if (version>=3 && version<4) {
        wkt_file=syscall($DV_GDAL_PATH+"/gdalinfo -wkt_format WKT1 -proj4 "+opts+" "+filename)
    } else {
        printf("Your version of GDAL (%f) is not supported\n",version)
        return(0)
    }
         
    #Setup the output structure
    struct={}
    struct.gdal_version=version
    struct.anc={}
    struct.anc.wkt=text(0)
    if(raw==1) {
        struct.anc.gdalinfo=wkt_file
    }

    #rip out and format the wkt.
    #search for the coordinate system or GCP projection (this is for non projected data that have gcps attached)
    coordline=maxpos(wkt_file==grep(wkt_file,"Coordinate\ System\ is")[,1])[2]
    if(wkt_file[:6,coordline+1]!="PROJCS" && wkt_file[:6,coordline+1]!="GEOGCS") {
        coordline=maxpos(wkt_file==grep(wkt_file,"GCP\ Projection\ =")[,1])[2]
        for(i=coordline+2;i<=length(wkt_file);i+=1) {
            if(wkt_file[1,i]!=" ") {
                ecoordline=i
                i=length(wkt_file)+1
            } 
        }
        proj=0
    } else {
        colon=grep(wkt_file,":")
        mline=maxpos(colon==grep(colon,"Coordinate\ System\ is")[,1])[2]
        ecoordline=maxpos(wkt_file==grep(wkt_file,colon[,mline+1,1])[,1])[2]
        proj=1
    }
    

    for(i=coordline+1;i         if(wkt_file[,i]!="PROJ.4 string is:") {
            struct.anc.wkt=cat(struct.anc.wkt,wkt_file[,i],axis=y)
        }
    }

    #get the NoData Value
    if(HasValue(grep(wkt_file,"NoData\ Value="))) {
        struct.ignore=atod(grep(wkt_file,"NoData\ Value")[16:,1])
    }

    #get the Bands Info
    if(HasValue(grep(wkt_file,"^Band\ "))) {
    struct.anc.bandcount=length(grep(wkt_file,"^Band\ "))
    }

    #handle the subdatasets    
    if(HasValue(grep(wkt_file,"Subdatasets:")[,1])) {
        sdsline=maxpos(wkt_file==grep(wkt_file,"Subdatasets:")[,1])[2]+1
        struct.anc.subdata={}
        struct.anc.subdata.name=text(0)
        struct.anc.subdata.description=text(0)
        
        for(i=sdsline;i<=length(wkt_file);i+=2) {
            if(strstr(wkt_file[,i],"SUBDATASET")>0) {
                struct.anc.subdata.name=cat(struct.anc.subdata.name,strsplit(wkt_file[,i],delim="=")[,2],axis=y)
            }
            if(strstr(wkt_file[,i],"SUBDATASET")>0) {
                struct.anc.subdata.description=cat(struct.anc.subdata.description,strsplit(wkt_file[,i+1],delim="=")[,2],axis=y)
            }
        }
    }

    #handle the metadata    
    if(HasValue(grep(wkt_file,"Metadata:")[,1])) {
        metaline=maxpos(wkt_file==grep(wkt_file,"Metadata:")[,1])[2]+1
        struct.anc.metadata={}
        
        for(i=metaline;i<=length(wkt_file);i+=1) {
            if(wkt_file[:2,i]=="  ") {
                tmp=strsplit(wkt_file[,i],delim="=")
                add_struct(struct.anc.metadata,name=trim_whitespace(tmp[,1]),value=tmp[,2])
            } else {
                i=length(wkt_file)+1
            }
        }

        #grab an xaxis if it exists
        if(HasValue(get_struct(struct.anc.metadata,"xaxis"))) {
            struct.xaxis=translate(atof(strsplit(struct.anc.metadata.xaxis)),y,z)
        }
    }


    #handle the gcps
    if(HasValue(grep(wkt_file,"GCP\\[")[,1])) {
        gcpline=maxpos(wkt_file==grep(wkt_file,"GCP\\[")[,1])[2]
        numgcps=length(grep(wkt_file,"GCP\\["))
     
        struct.anc.gcps=text(0)
        for(i=gcpline;i<=gcpline+numgcps*2-1;i+=1) {
            if(wkt_file[:4,i]=="GCP[") {
                tmp=strsub(strsub(trim_whitespace(wkt_file[,i+1]),"\\)",""),"\\(","")
                tmp=strsub(strsplit(tmp,delim=" "),","," ")
                struct.anc.gcps=cat(struct.anc.gcps,tmp[,1]//" "//tmp[,3],axis=y)
            }
        }
    }

    if(proj==1) {
        #get the proj4 string
        if(HasValue(grep(wkt_file,"PROJ.4\ string\ is:"))) {
            pos=maxpos(wkt_file==grep(wkt_file,"PROJ.4\ string\ is:")[,1])[2]
            struct.anc.proj4=wkt_file[,pos+1]
        }
    
        #get the projection
        if(HasValue(grep(wkt_file,"PROJECTION"))) {
            tmp=grep(wkt_file,"PROJECTION")
            tmppos=strstr(tmp,"\"")
            tmp=tmp[tmppos+1:,1]
            tmppos=strstr(tmp,"\"")
            tmp=tmp[:tmppos-1,1]
            struct.projection=tmp
        }
    
        #get the spheroid for easy viewing if an ellipsoid was used
        if(HasValue(grep(wkt_file,"SPHEROID"))) {
            struct.spheroid={}
            tmp=grep(wkt_file,"SPHEROID")
            tmppos=strstr(tmp,"\"")
            tmp=tmp[tmppos+1:,1]
            tmppos=strstr(tmp,"]]")
            tmp=tmp[:tmppos-1,1]
            tmppos=strstr(tmp,"\",")
            name=tmp[:tmppos-1]
            tmp=tmp[tmppos+2:]
            tmppos=strstr(tmp,",")
            radius=tmp[:tmppos-1]
            flattening=tmp[tmppos+1:]
            struct.spheroid.name=name
            struct.spheroid.radius=radius
            struct.spheroid.iflattening=atod(flattening)+""
        }
    
        #get the origin
        if(HasValue(grep(wkt_file,"Origin\ =\ "))) {
            struct.anc.origin=atod(strsplit(grep(wkt_file,"Origin\ =\ ")[11:],","))
        }
            
        #get the Pixel size
        if(HasValue(grep(wkt_file,"Pixel\ Size\ =\ "))) {  
            struct.anc.pixel_size=atod(strsplit(grep(wkt_file,"Pixel\ Size\ =\ ")[15:],","))
            #this seems to cause some weirdness...x vs y resolution vary
            #struct.resolution=avg(abs(struct.anc.pixel_size),ignore=0)
            struct.resolution=struct.anc.pixel_size[,1]
        }
    
        #calculate the spo/lpo
        if(HasValue(get_struct(struct.anc,"origin")) && HasValue(get_struct(struct.anc,"pixel_size"))) {
            struct.x=struct.anc.origin[,1]/struct.anc.pixel_size[,1]
            struct.y=struct.anc.origin[,2]/struct.anc.pixel_size[,2]
        }  

        #get the lat/lon
        if(HasValue(grep(wkt_file,"Corner\ Coordinates:"))) {
            cline=maxpos(wkt_file==grep(wkt_file,"Corner\ Coordinates:")[,1])[2]+1
            struct.anc.spo=struct.anc.lpo=struct.anc.lon=struct.anc.lat=create(1,5,1,start=0,step=0,format=float)

      lonlattest=0
      for(j=0;j<=4;j+=1) {
        tmp=strsplit(wkt_file[,cline+j],delim="(")
        xy=atod(strsplit(tmp[,2]))
        struct.anc.spo[,j+1]=xy[,1]
        struct.anc.lpo[,j+1]=xy[,2]
                      
        if(length(tmp)==3) {
          lonlat=strsplit(tmp[,3])
          struct.anc.lon[,j+1]=latlonDMS2dec(strsub(strsub(lonlat[,1],")",""),"\\(",""))
          struct.anc.lat[,j+1]=latlonDMS2dec(strsub(strsub(lonlat[,2],")",""),"\\(",""))
          lonlattest=1
        }
            }
        
      if(lonlattest==1) {    
            #set the min/max/center lon/lat
              minlat=min(struct.anc.lat)
              minlon=min(struct.anc.lon)
              maxlat=max(struct.anc.lat)
              maxlon=max(struct.anc.lon)
              struct.ul=struct.anc.lat[,1]//struct.anc.lon[,1]
              struct.ll=struct.anc.lat[,2]//struct.anc.lon[,2]
              struct.ur=struct.anc.lat[,3]//struct.anc.lon[,3]
              struct.lr=struct.anc.lat[,4]//struct.anc.lon[,4]
              struct.anc.center=struct.anc.lat[,5]//struct.anc.lon[,5]
      }
        }
    }

    if(length(struct.anc.wkt)==0) remove_struct(struct.anc,"wkt")

    #return the data
    if(v!=-1) verbose=3
    return(struct)
}
    
    
    
define read_geo(struct,data,raw,subdata,band,v) {
    
    if($ARGC<1) {
        printf("\nThis function reads a Geo-Aware file (e.g. GeoTIFF, ISIS2/3, Envi, etc.)\n")
        printf("The input data must be a format davinci and gdal understand\n\n")
        printf("$1=filename\n\n")
        printf("Options:\n")
        printf("\tdata=return the data (Default=1)\n")
        printf("\tstruct=return the struct (Default=1)\n")
        printf("\traw=return the raw gdalinfo (Default=0)\n")
        printf("\tband=read only the specified band 0=All (Default=0)\n\n")
        printf("\tsubdata=specify the number of the subdataset to read (Default = -32768)\n")
        printf("\tif none is specified it will be treated as if there are no subdatasets\n")
        printf("\tif subdatasets exist and a subdata #is not specified the list of subdatasets is returned\n\n")
        printf("Returns a standard davinci Geo-Struct\n\n")
        printf("NOTE: This function requires $DV_GDAL_PATH\n")
        printf("and gdal version >=1.8\n\n")
        printf("c.edwards 4/9/13\n")
        return(null)
    }    

    #input handling
    filename=$1
    if(HasValue(data)==0) data=1
    if(HasValue(struct)==0) struct=1
    if(HasValue(raw)==0) raw=0
    if(HasValue(band)==0) band=0
    if(HasValue(subdata)==0) subdata=-32768
    if(HasValue(v)==0) v=0
    if(data==0 && struct==0) {
        printf("\nData and struct cannot both be 0\n")
        printf("Please select one option\n\n")
        return(null)
    }


    #deal with remote files
    remote=0
    prefix=cat("http://","https://","ftp://","sftp://","file:///",axis=y)
    for(i=1;i<=length(prefix);i+=1) {
        if(filename[:length(prefix[,i])]==prefix[,i]) {
            remote=1
        }
    }
    
    if(remote==1) {
        newfile=$TMPDIR+"/"+basename(filename)+".copy"
        filename=copy(filename,newfile,force=1)
    }

    #get the metadata and prepare the input
    basename=basename(filename)
    out=read_geometa(filename,raw=raw,v=v)
    workingname=$TMPDIR+"/gdal_io.tiff"

    #pretty print all the subdatasets 
    if(HasValue(get_struct(out.anc,"subdata")) && subdata==-32768) {
        printf("\nERROR: You must select a subdata # to read\n\n")
        printf("The avilable Subdatasets are:\n")
        
        for(i=1;i<=length(out.anc.subdata.description);i+=1) {
            tmp=strsplit(strsub(out.anc.subdata.description[2:,i],"\\]",","),delim=",")
            tmp2=strsplit(strsub(tmp[,2],"\\)",""),delim="(")
            printf("\t%.2d) %s: %s array of %s\n",i,trim_whitespace(tmp2[,1]),tmp[,1],tmp2[,2])
        }
        printf("\n")
        return(null)
    }
 
    if(subdata==0) {
        subdata=create(length(out.anc.subdata.name),1,1,start=1,step=1)
    }
    
    bandstr=""
    if(band!=0) {
        bandstr="-b "+band
    }

    #handle all the subdatasets (if we have them, otherwise just read the data) 
    if(subdata!=-32768) {
        tmp={}
        for(i=1;i<=dim(subdata)[1];i+=1) {
            
            #for each subdataset read in the data
            filename=out.anc.subdata.name[,subdata[i]]
            syscall(sprintf($DV_GDAL_PATH+"/gdal_translate -co \"BIGTIFF=NO\" %s -of GTiff %s %s",bandstr,filename,workingname))
            verbose=0
            if(dim(subdata)[1]>1) {
                add_struct(tmp,name=sprintf("subdata%.2d",subdata[i]),value=read(workingname))
            } else {
                tmp=read(workingname)
                out.w=dim(tmp)[1]
                out.h=dim(tmp)[2]
            }
            if(v!=-1) verbose=3
        }
    } else {
        verbose=0

        #translate and read in the data
        syscall(sprintf($DV_GDAL_PATH+"/gdal_translate -co \"BIGTIFF=NO\" %s -of GTiff %s %s",bandstr,filename,workingname))
        filename=$TMPDIR+"/"+basename+".tiff"
        tmp=read(workingname)
        out.w=dim(tmp)[1]
        out.h=dim(tmp)[2]
        if(v!=-1) verbose=3
    }

    #clean up the subdataset names 
    if(struct==1 && subdata!=-32768) {
        subdatatmp=text(0)

        for(i=1;i<=dim(subdata)[1];i+=1) {
            subdatatmp=cat(subdatatmp,strsplit(out.anc.subdata.description[,subdata[i]],delim=" ")[,2],axis=y)
        }
        out.dataname=subdatatmp
    }

    #if we want a structure (if not this uses all of gdals reading capabilites for davinci to act like read())
    if(struct==1) {
        #the attach the data
        if(data==1) {
            out.data=tmp
        }
    } else {
        out=tmp
    }

    #cleanup and return the data
    syscall("rm "+workingname+"*")
    return(out)
}



define write_geotiff(force,v,subdata,a_srs,addo,addotype,addoscales,envi,fits) {

    if($ARGC<2) {
        printf("\nThis function writes a GeoTIFF file\n")
        printf("The input data must be a structure from read_geo()\n\n")
        printf("$1=the davinci Geo-Struct\n")
        printf("$2=the output filename\n\n")
        printf("Options:\n")
        printf("\tenvi=write an envi file, default=0\n")
        printf("\tfits=write a fits file, default=0\n")
        printf("\tforce=force the overwrite of exiting data\n")
        printf("\tsubdata=specify the subdataset to write (only one is supported at this time)\n")
        printf("\ta_srs=force assign a projection (Default=\"\")\n")
        printf("\taddo=add pyramid overviews (Default=\"\")\n")
        printf("\taddoscales=scales of the overviews to add (Default=2//4//8//16//32//64//128)\n")
        printf("\taddotype=sub-sampling type for addo option (Default=\"average\")\n")
        printf("\t\tsupported types are are: \"nearest\",\"average\",\"gauss\",\"cubic\"\n")
        printf("\t\t                         \"average_mp\",\"average_magphase\",\"mode\"\n\n")
        printf("NOTE: This function requires $DV_GDAL_PATH\n")
        printf("and gdal version >=1.8\n\n")
        printf("WARNING: This function will output bad geo-referenced data\n")
        printf("if you change the data array size\n\n")
        printf("c.edwards 4/9/13\n")
        return(null)
    }
    
    #handle the input
    outdata=$1
    outname=$2
    outbase=basename(outname,".tiff")
    if(HasValue(get_struct(outdata,"data"))==0) {
        printf("\nERROR: No .data element found in the Geo-Struct\n\n")
        return(null)
    }

    if(HasValue(force)==0) force=0
    if(HasValue(v)==0) v=0    
    if(HasValue(envi)==0) envi=0
    if(HasValue(fits)==0) fits=0

    addotypestr=""
    if(HasValue(addotype)==0) {    
        addotypestr="-r average"
    } else {
        addotypestr="-r "+addotype
    }

    addoscalesstr=""
    if(HasValue(addoscales)) {    
        for(i=1;i<=dim(addoscales)[1];i+=1)    {
            addoscalesstr=addoscalesstr+sprintf("%i ",addoscales[i])
        }
    } else {
        addoscalesstr="2 4 8 16 32 64 128"
    }

    if(HasValue(subdata)==0) subdata=-32768
    if(type(outdata.data)=="STRUCT" && subdata==-32768) {
        printf("\nERROR: Please select a subdataset for writing by subdata=#\n")
        printf("Currently only one subdataset can be written at a time\n\n")
        return(null)
    }

    #first we write out a tiff
    if(v==-1) verbose=0
    if(fexists(outname)==0 || force==1) {
        if(subdata!=-32768) {
            outdata.data=eval(sprintf("outdata.data.subdata%.2d",subdata))
        }
        write(outdata.data,$TMPDIR+"/"+outbase+".tmp.tiff",tiff,force=1)
    } else {
        printf("\nFile Exists: %s\n",outname)
        printf("Use force=1 to overwrite\n\n")
        return(null)
    }

    #get the data dimension
    dim=dim(outdata.data)

    #assemble all the gdal options (we have to assign an srs)
    srsstr=""
    if(HasValue(get_struct(outdata.anc,"wkt"))) {
     #build the nice looking wkt
     for(i=1;i<=length(outdata.anc.wkt);i+=1) {
            srsstr+=trim_whitespace(outdata.anc.wkt[,i])
        }
        if(length(outdata.anc.wkt)>0) srsstr=sprintf(" -a_srs '%s'",srsstr)
    } else if (HasValue(get_struct(outdata.anc,"a_srs"))) {
        srsstr=sprintf(" -a_srs '%s'",outdata.anc.a_srs)     
    } else if(HasValue(a_srs)){
        srsstr=sprintf(" -a_srs '%s'",a_srs)
    } else {
        printf("Writing data without a spatial reference system\n")
    }

    #make a blank metadata structure if we don't have one and we do have an xaxis
    if(HasValue(get_struct(outdata.anc,"metadata"))==0 && HasValue(get_struct(outdata,"xaxis"))){ 
        outdata.anc.metadata={}
    }

    metastr=""
    if(HasValue(get_struct(outdata.anc,"metadata"))) {

        #format the xaxis element to be written as a metadata element
        if(HasValue(get_struct(outdata,"xaxis"))) {
            outdata.anc.metadata.xaxis=""
            for(i=1;i<=dim(outdata.xaxis)[3];i+=1) {
                outdata.anc.metadata.xaxis=cat(outdata.anc.metadata.xaxis,",",outdata.xaxis[,,i]+"",axis=x)
            } 
            outdata.anc.metadata.xaxis=outdata.anc.metadata.xaxis[2:]
        }

        keys=get_struct_key(outdata.anc.metadata)

        for(i=1;i<=length(keys);i+=1) {
            val=eval("outdata.anc.metadata."+keys[,i])
            metastr+=sprintf(" -mo '%s=%s'",keys[,i],val)
        }
    }

    #deal with the ground control points
    gcpstr=""
    if(HasValue(get_struct(outdata.anc,"gcps"))) {
        gcpfile=$TMPDIR+"/"+outbase+".gcps"
        gcpstr=" --optfile "+gcpfile
        tmp=text()
        for(i=1;i<=length(outdata.anc.gcps);i+=1) {
            tmp=cat(tmp,"-gcp "+outdata.anc.gcps[,i],axis=y)
        }
        write(tmp,gcpfile,ascii,force=1)
    }

    #if lpo/spo exist we use them so gdal can calculate the pixel size
    ullrstr=""
    if(HasValue(get_struct(outdata.anc,"lpo")) && HasValue(get_struct(outdata.anc,"spo"))) {
        ullrstr=sprintf(" -a_ullr %f %f %f %f",outdata.anc.spo[,1],outdata.anc.lpo[,1],outdata.anc.spo[,4],outdata.anc.lpo[,4])
    }

    #get the ignore value from the struct
    nodatastr=""
    if(HasValue(get_struct(outdata,"ignore"))) {
        nodatastr=sprintf(" -a_nodata '%.20g' ",outdata.ignore)
    }

    #assemble the command
    if(envi==1) {
        command=sprintf($DV_GDAL_PATH+"/gdal_translate %s%s%s%s%s -of ENVI %s %s",metastr,gcpstr,srsstr,ullrstr,nodatastr,$TMPDIR+"/"+outbase+".tmp.tiff",outname)
        outtype="ENVI"
    } else if(fits==1) {
        command=sprintf($DV_GDAL_PATH+"/gdal_translate %s%s%s%s%s -of FITS %s %s",metastr,gcpstr,srsstr,ullrstr,nodatastr,$TMPDIR+"/"+outbase+".tmp.tiff",outname)
        outtype="FITS"
    } else {
        command=sprintf($DV_GDAL_PATH+"/gdal_translate -co \"COMPRESS=DEFLATE\" -co \"BIGTIFF=NO\" %s%s%s%s%s -of GTiff %s %s",metastr,gcpstr,srsstr,ullrstr,nodatastr,$TMPDIR+"/"+outbase+".tmp.tiff",outname)
        outtype="GeoTIFF"
    }

    #attach the ancellary data using gdal_translate
    if(v!=-1) printf("Attaching Ancellary Data to %s: %ix%ix%i %s File....",outname,dim[1],dim[2],dim[3],outtype)
    if(v==1) {
        printf("%s\n",command)    
        system(command)
    } else {
        syscall(command)
    }
  if(v!=-1)    printf("Done.\n")

    if(HasValue(addo)) {
        command=sprintf($DV_GDAL_PATH+"/gdaladdo %s %s %s",addotypestr,outname,addoscalesstr)
        if(v!=-1) printf("Attaching Overviews to %s: %s....",outname,addoscalesstr)
        if(v==1) {
            printf("%s\n",command)    
            system(command)
        } else {
            syscall(command)
        }
      if(v!=-1)    printf("Done.\n")
    }
}


define add_gcps_geo(elev,sampling,xsampling,ysampling,ignore) {
    
    if($ARGC<3) {
        printf("\nAdd GCPS to a davinci Geo-Struct\n")
        printf("This will sample a lat/lon/(optional elevation) backplane to generate\n")
        printf("the appropriate structure mapping for GDAL\n\n")
        printf("$1 = the davinci Geo-Struct\n")
        printf("$2 = a longitude backplane the same size as the .data of $1\n")
        printf("$3 = a latitude backplane the same size as the .data of $1\n\n")
        printf("Options:\n")
        printf("\telev = an elevation backplane the same size as the .data of $1 (optional)\n")
        printf("\tsampling = x/y pixel sampling (# of x/y gcps) (Default = 10)\n")
        printf("\txsampling = x pixel sampling (# of x gcps) (Default = sampling)\n")
        printf("\tysampling = y pixel sampling (# of y gcps) (Default = sampling)\n")
    printf("\tignore = ignore lat/lon points that have this value (Default = -32768)\n\n")
        printf("c.edwards 4/9/13\n")
        return(null)
    }

    #input handling
    struct=$1
    lon=$2
    lat=$3

    #error handling
    if(HasValue(struct.data)==0){
        printf("$1 does not appear to be a valid davinci Geo-Struct\n")
        return(null)
    }

    if(HasValue(lon)==0 || dim(lon)!=dim(struct.data)) {
        printf("$2 does not appear to be a longitude backplane\n")
        return(null)
    }

    if(HasValue(lat)==0 || dim(lat)!=dim(struct.data)) {
        printf("$3 does not appear to be a latitude backplane\n")
        return(null)
    }


    #deal with the option of having elevation
    if(HasValue(elev)==0) {
        elev=float(byte(lat)*0.)
    }
 
    if(dim(elev)!=dim(struct.data)) {
        printf("$4 does not appear to be an elevation backplane\n")
        return(null)
    }

    #more input handling
    if(HasValue(sampling)==0) sampling=10
    if(HasValue(ysampling)==0) ysampling=sampling
    if(HasValue(xsampling)==0) xsampling=sampling
  if(HasValue(ignore)==0) ignore=-32768

    #setup the output gcp string
    gcpstr=text(0)

    #claculate the required step to have evenly spaced gcps
    xstep=dim(struct.data)[1]/float(xsampling-1)
    ystep=dim(struct.data)[2]/float(ysampling-1)

    #calculate the position of the gcps
    for(i=0;i         for(j=0;j
            x=int(ceil(i*xstep))
            y=int(ceil(j*ystep))

            #make sure we don't overstep the image bounds
            if(x>=dim(struct.data)[1]) x=dim(struct.data)[1]
            if(x<=0) x=1
            if(y>=dim(struct.data)[2]) y=dim(struct.data)[2]
            if(y<=0) y=1

            #turn them into nice looking gcps
            tmp=sprintf("%i %i %f %f %f",x,y,lon[x,y],lat[x,y],elev[x,y])
            #printf("%i %i %f %f %f\n",x,y,lon[x,y],lat[x,y],elev[x,y])

            #cat all the gcps together
      if(lon[x,y]!=ignore && lat[x,y]!=ignore) {
        gcpstr=cat(gcpstr,tmp,axis=y)
      }
        }
    }

    #return the output
    struct.anc.gcps=gcpstr
    return(struct)
}



define proj_geo(resolution,resampling,ignore,opts,v,a_srs,subdata,raw,te,match) {

    if($ARGC==0 || ($ARGC==1 && HasValue(match)==0)) {
        printf("\nThis function reprojects Geo-Struct or Geo-Aware file\n\n")
        printf("$1=the davinci Geo-Struct or a path to a Geo-Aware File\n")
        printf("$2=target projection argument (either a proj string or wkt)\n\n")
        printf("Options:\n")
        printf("\tresolution=resolution of output in georeferenced units (Default=native)\n")
        printf("\tresampling=resampling type (near,bilinear,cubic,cubicspline,lanczos, Default=\"near\")\n")
        printf("\tignore=ignore value for the data (Default=\"\")\n")
        printf("\topts=additional gdalwarp options (Default=\"\")\n")
        printf("\ta_srs=projection of the source (either a proj string or wkt), assigned by default values in Geo-Struct\n")
        printf("\tte=extent xmin//ymin//xmax//ymax (Default=from input)\n")
        printf("\tmatch=match the projection/extent/resolution of the supplied geostruct, with overrides from other parameters\n")
        printf("\traw=read the raw gdalinfo data into the structure\n")
        printf("\tsubdata=project out only the subdataset specified. Currently it only supports the projecting of 1 subdataset\n\n")
        printf("NOTE: This function requires $DV_GDAL_PATH\n")
        printf("and gdal version >=1.8\n\n")
        printf("c.edwards 4/9/13\n")
        return(null)
    }

    #setup the input/srs 
    #eventually we should have a nice suite of t_srs from another function
    input=$1
    if($ARGC==2) t_srs=$2
    if(HasValue(v)==0) v=0
    if(HasValue(raw)==0) raw=0

  #match another geostruct
  if(HasValue(match)!=0) {
    if(HasValue(te)==0) te=min(match.anc.spo)//min(match.anc.lpo)//max(match.anc.spo)//max(match.anc.lpo)
    if(HasValue(t_srs)==0) t_srs=match.anc.wkt
    if(HasValue(resolution)==0) resolution=match.resolution
  }

    #allow for any additional options (but they will be in gdal format)
    optstr="-multi "
    if(HasValue(opts)!=0) {
        optstr=opts+" -multi " 
    }

    #set the resolution
    resstr=""
    if(HasValue(resolution)!=0) {
        resstr="-tap -tr "+resolution+" "+resolution+" "
    } else {
        if(HasValue(get_struct(input,"resolution"))) {
            resstr="-tap -tr "+input.resolution+" "+input.resolution+" "
        } 
    }

    #set the extent
    testr=""
    if(HasValue(te)!=0) {
        testr=sprintf("-te %f %f %f %f ",te[1],te[2],te[3],te[4])
    }

    #set the default interpolation to bilinear
    resampstr="-r near "
    if(HasValue(resampling)!=0) {
        resampstr="-r "+resampling+" "
    }

    #set the ignore values (src and target are going to be the same)
    ignorestr=""
    if(HasValue(ignore)!=0) {
        ignorestr=sprintf("-srcnodata %f -dstnodata %f ",ignore,ignore)
    }
    opts=resstr+resampstr+ignorestr+testr+optstr

    #set the default subdata
    if(HasValue(subdata)==0) subdata=-32768

    #parse the t_srs
    if(type(t_srs)=="STRING") { 
        length=1
    } else if(type(t_srs)=="TEXT") {
        length=length(t_srs)
    }
    
    srsstr=""
    #cleanup the whitespace
    for(i=1;i<=length;i+=1) {
        srsstr+=trim_whitespace(t_srs[,i])
    }
    t_srs=srsstr
    
    #we reproject the data on disk (maybe its gcps or something)
    if(type(input)=="STRING") {
        file=input
    
        #deal with remote data
        remote=0
        prefix=cat("http://","https://","ftp://","sftp://","file:///",axis=y)
        for(i=1;i<=length(prefix);i+=1) {
            if(file[:length(prefix[,i])]==prefix[,i]) {
                remote=1
            }
        }
    
        if(remote==1) {
            newfile=$TMPDIR+"/"+basename(file)+".copy"
            file=copy(file,newfile,force=1)
        }
    } else if (type(input)=="STRUCT") {

        #write the data to disk
        file=$TMPDIR+"/proj_geo_orig.tiff"
        if(HasValue(a_srs)) {
            write_geotiff(input,file,force=1,a_srs=a_srs,v=v,subdata=subdata)
        } else {
            write_geotiff(input,file,force=1,v=v,subdata=subdata)
        }
    } else {
        printf("Sorry must either project a davinci Geo-Struct\n")
        printf("or a file on disk\n")
        return(null)
    }

    #generate the warp command
    command=$DV_GDAL_PATH+"/gdalwarp -co \"BIGTIFF=NO\" -overwrite "+opts+" -t_srs '"+t_srs+"' "+file+" "+$TMPDIR+"/proj_geo_proj.tiff"

    #this is simply to make it a bit more verbose (display the gdal progress bar)
    if(v==1) {
        printf("%s\n",command)
        system(command)
    } else {
        syscall(command)
    }

    #read in the new projected data
    out=read_geo($TMPDIR+"/proj_geo_proj.tiff",raw=raw)

    #cleanup and output the data
    syscall("rm "+$TMPDIR+"/proj_geo_proj.tiff "+$TMPDIR+"/proj_geo_orig.tiff")
    return(out)
}


define UTMzone_to_CentralMeridian(){
    if($ARGC==0) {
        printf("\nDetermines the central meridian for the given UTM (on Earth) zone\n\n")
        printf("$1 - An integer value designating the UTM zone, range [1:60]\n")
        printf("Returns - the central meridian (-180 to 180) for the given UTM zone, in degrees\n\n")
        printf("c.edwards 8-28-2011\n")
        return(null)
    }

    #handle the input
    zone=$1 

    #reset the zone limits
    if(zone<=0) zone=1
    if(zone>60) zone=60
    
    #calculate the central meridian
    cmeridian = (-183.0 + (zone * 6.0));
    
    #return the output
    return(cmeridian);
}



define CentralMeridian_to_UTMzone(){
    if($ARGC==0) {
        printf("\nDetermines the UTM zone for a given central meridian (-180 to 180)\n\n")
        printf("$1 - the central meridian for the desired UTM zone\n")
        printf("Returns - the given UTM zone\n\n")
        printf("c.edwards 8-28-2011\n")
        return(null)
    }

    #handle the input
    cmeridian=$1
    
    #calculate the zone
    zone=int(ceil((cmeridian + 180.0)/6.))

    #reset the zone limits
    if(zone>60) zone=60
    if(zone<=0) zone=1

    #output the output
    return(zone);
}



define get_proj(source) {

    if($ARGC==0) {
        printf("\nGet a Spatial Reference System\n")
        printf("Queries spatialreference.org\n\n")
        printf("$1=SRS number\n\n")
        printf("Options:\n")
        printf("\tsource=SRS source \"iau2000\", \"epsg\", or \"esri\", (Default=\"iau2000\")\n\n")
        printf("c.edwards 5/10/13\n")
        return(null)
    }

    #input handling
    srsnumber=$1
    if(HasValue(source)==0) source="iau2000"
    if(source!="epsg" && source!="iau2000" && source!="esri") {
        printf("Error: source must be either epsg, esri, or iau2000\n")
        return(null)
    }

    #setup the output
    struct={}
    struct.anc={}
    
    #get the projections from the webpage
    wkt=read_lines("http://spatialreference.org/ref/"+source+"/"+srsnumber+"/prettywkt/")
    proj=read_lines("http://spatialreference.org/ref/"+source+"/"+srsnumber+"/proj4/")

    #sometimes we don't get a proj string
    if(length(proj)!=0) struct.anc.proj4=proj

    #parse the spheroid from the wkt
    if(HasValue(grep(wkt,"SPHEROID"))) {
        struct.spheroid={}
        tmp=grep(wkt,"SPHEROID")
        tmppos=strstr(tmp,"\"")
        tmp=tmp[tmppos+1:,1]
        tmppos=strstr(tmp,"]]")
        tmp=tmp[:tmppos-1,1]
        tmppos=strstr(tmp,"\",")
        name=tmp[:tmppos-1]
        tmp=tmp[tmppos+2:]
        tmppos=strstr(tmp,",")
        radius=tmp[:tmppos-1]
        flattening=tmp[tmppos+1:]
        struct.spheroid.name=name
        struct.spheroid.radius=radius
        struct.spheroid.iflattening=atod(flattening)+""
    }

    #parse the projection from the wkt
    if(HasValue(grep(wkt,"PROJECTION"))) {
        tmp=grep(wkt,"PROJECTION")
        tmppos=strstr(tmp,"\"")
        tmp=tmp[tmppos+1:,1]
        tmppos=strstr(tmp,"\"")
        tmp=tmp[:tmppos-1,1]
        struct.projection=tmp
    }

    #return the output
    struct.anc.wkt=wkt
    return(struct)
}



define find_proj(print) {

    if($ARGC==0) {
        printf("\nSearch for a Spatial Reference System\n")
        printf("Queries spatialreference.org\n\n")
        printf("$1=search term\n\n")
        printf("Options:\n")
        printf("\tprint=print the results (Default=1)\n\n")
        printf("c.edwards 5/10/13\n")
        return(null)
    }

    #setup input
    if(HasValue(print)==0) print=1
    
    #get only the lines that match the search parameter
    search=$1
    tmp=grep(read_lines("http://spatialreference.org/ref/?search="+search+""),"

  •     #if we find no lines
        if(length(tmp)==0) {
            printf("No projections found\n")
            return(null)
        }

        #split based on > to separate the html code
        tmp2=strsplit(tmp,delim=">")

        #setup the output structure
        vals={}
        vals.srsnumber=text(0)
        vals.source=text(0)
        vals.description=text(0)

        #pretty print output
        if(print!=0) {
            printf("\n\tSRS\t\tDescription\n")
            printf("\t--------------------------------\n")
        }

        #fill out the source,srs and description structure for output
        count=0
        for(i=1;i<=length(tmp2);i+=1) {

            #split on the other > to further parse the result from spatialreference.org
            split=strsplit(strsub(tmp2[i][,3],"<",":"),delim=":")
            if(trim_whitespace(split[,1])!="SR-ORG") {
                count+=1
                vals.source=cat(vals.source,trim_whitespace(split[,1]),axis=y)
                vals.srsnumber=cat(vals.srsnumber,trim_whitespace(split[,2]),axis=y)
                vals.description=cat(vals.description,trim_whitespace(strsplit(strsub(tmp2[i][,4],"<",":"),delim=":")[,2]),axis=y)

                #pretty print the output
                if(print!=0) printf("\t%s:%s -\t%s\n",vals.source[,count],vals.srsnumber[,count],vals.description[,count])
            }
        }
        if(print!=0) printf("\n")
        return(vals)
    }



    define read_geoshape(v,opts) {

        if($ARGC==0) {
            printf("\nLoad any shapefile type supported by GDAL\n")
            printf("by translating to a CSV shapefile into a GeoShape-Struct\n")
            printf("Input is not translated if it is already a CSV shapefile\n\n")
            printf("$1=filename and path\n\n")
            printf("Options:\n")
            printf("\topts=additional ogr2ogr options (Default=\"\")\n\n")
            printf("NOTE: This function requires $DV_GDAL_PATH\n")
            printf("and gdal version >=1.8\n\n")
            printf("c.edwards 5/12/13\n")
            return(null)
        }

        #input handing
        filename=$1
        if(HasValue(v)==0) v=0

        #allow for any additional options (but they will be in gdal format)
        optstr=""
        if(HasValue(opts)!=0) {
            optstr=opts+" "
        }

        #deal with remote files
        remote=0
        prefix=cat("http://","https://","ftp://","sftp://","file:///",axis=y)
        for(i=1;i<=length(prefix);i+=1) {
            if(filename[:length(prefix[,i])]==prefix[,i]) {
                remote=1
            }
        }

        if(remote==1) {
            newfile=$TMPDIR+"/"+basename(filename)+".copy"
            filename=copy(filename,newfile,force=1)
        }

        if(fexists(filename)==0) {
            printf("Couldn't find file: %s\n",filename)
            return(null)
        }

        #set the working file names
        basename=basename(filename)

        #build the command
        #if we already have csv...just read it...we don't need gdal to confuse things!
        if(strstr(basename,".csv")==0) {
            workingname=$TMPDIR+"/reading/gdal_shape.reading.csv"
            syscall("mkdir -p "+dirname(workingname))
            if(fexists(workingname)) syscall("rm "+workingname)
            command=$DV_GDAL_PATH+"/ogr2ogr -lco GEOMETRY=AS_WKT "+optstr+" -f CSV "+workingname+" "+filename
            #run the command
            if(v==1) {
                printf("%s\n",command)
                system(command)
            } else {
                syscall(command)
            }
        } else { 
            if(v==1) printf("skipping gdal\n")
            workingname=filename
        }

        #read the translated data
        out=load_csv(workingname,sep=",")

        #check to see if wkt and geometry exist
        #set wkt to geometry if wkt exitst and geometry doesn't
        if(HasValue(get_struct(out,"geometry"))==1) {
            out.wkt=remove_struct(out,"geometry")
        }

        #cleanup and output
        return(out)
    }



    define write_geoshape(v,force,a_srs,t_srs,s_srs,opts,type) {

        if($ARGC<2) {
            printf("\nWrite a Shapefile to disk from a GeoShape-Struct (wkt=geometry field)\n\n")
            printf("$1=GeoShape-Struct\n")
            printf("$2=filename and path\n\n")
            printf("Options:\n")
            printf("\tforce=overwrite any existing files (Default=0)\n")
            printf("\tt_srs=projction of the target (reprojection will occur, Default=\"\")\n")
            printf("\ts_srs=projection of the source (Default=\"\")\n")
            printf("\ta_srs=projection of the output (reprojection will not occur, Default=\"\")\n")
            printf("\topts=additional ogr2ogr options (Default=\"\")\n")
            printf("\ttype=set the ouptut type from ogr2ogr (Default=\"CSV\")\n\n")
            printf("\tCommon output types:\n")
            printf("\t\t\"CSV\", \"ESRI Shapefile\", \"KML\", \"MySQL\",\"PostgrSQL\"\n\n")    
            printf("c.edwards 5/12/13\n")
            return(null)
        }

        #input handling
        struct=$1
        outname=$2
        if(HasValue(v)==0) v=0
        if(HasValue(force)==0) force=0
        if(HasValue(type)==0) type="CSV"

        #handle other gdal options
        optstr=""
        if(HasValue(opts)!=0) {
            optstr=opts+" "
        }

        #assign a target srs if set
        t_srsstr=""
        if(HasValue(t_srs)) {
            #parse the t_srs
            if(type(t_srs)=="STRING") {
                length=1
            } else if(type(t_srs)=="TEXT") {
                length=length(t_srs)
            }

            srsstr=""
            #cleanup the whitespace
            for(i=1;i<=length;i+=1) {
                srsstr+=trim_whitespace(t_srs[,i])
            }
            t_srsstr="-t_srs '"+srsstr+"' "
        }

        #assign an output srs if set
        a_srsstr=""
        if(HasValue(a_srs)) {
            #parse the a_srs
            if(type(a_srs)=="STRING") {
                length=1
            } else if(type(a_srs)=="TEXT") {
                length=length(a_srs)
            }

            srsstr=""
            #cleanup the whitespace
            for(i=1;i<=length;i+=1) {
                srsstr+=trim_whitespace(a_srs[,i])
            }
            a_srsstr="-a_srs '"+srsstr+"' "
        }

        #assign a source srs if set
        s_srsstr=""
        if(HasValue(s_srs)) {
            #parse the s_srs
            if(type(s_srs)=="STRING") {
                length=1
            } else if(type(s_srs)=="TEXT") {
                length=length(s_srs)
            }

            srsstr=""
            #cleanup the whitespace
            for(i=1;i<=length;i+=1) {
                srsstr+=trim_whitespace(s_srs[,i])
            }
            s_srsstr="-s_srs '"+srsstr+"' "
        }

        #check for file existance and the force option
        if(fexists(outname)==1 && force==0) {
            printf("\nFile Exists: %s\n",outname)
            printf("Use force=1 to overwrite\n\n")
            return(null)
        } else {
            if(fexists(outname)) syscall("rm "+outname)
        }


        #if we find and underscore and one of the types above
        #replace the _type with a :type (for JMARS)
        keys=get_struct_key(struct)

        #generate the apprpriate header
        out=text(0)
        tmp=""
        for(i=1;i<=length(keys);i+=1) {
            tmp=cat(tmp,",",""+keys[,i]+"",axis=x)
        }
        out=cat(out,tmp,axis=y)

        #fill out the text array because write_csv changes : to _
        for(i=1;i<=length(struct[1]);i+=1) {
            tmp=""
            for(j=1;j<=length(struct);j+=1) {
                tmp=cat(tmp,",","\""+struct[j][,i]+"\"",axis=x)
            }
            out=cat(out,tmp,axis=y)
        }

        #strip off the first 2 values because they are a comma and a space
        out=out[2:]
        tmpname=$TMPDIR+"/writing/gdal_shape.writing.csv"
        syscall("mkdir -p "+dirname(tmpname))
        write(out,tmpname,ascii,force=1)

        #we exclude "wkt" from the fields to write because it breaks so many things...
        #davinci will seg fault if more than one key is there, and ogr2ogr complains like crazy    
        fields=""
        for(i=1;i<=length(keys);i+=1) {
            if(keys[,i]!="wkt") {
                fields+=","+keys[,i]
            }
        }
        fields=fields[2:]

        #build the command to translate to any output type
        if(fexists(outname)) syscall("rm "+outname)
        command=$DV_GDAL_PATH+"/ogr2ogr "+optstr+s_srsstr+t_srsstr+a_srsstr+" -select '"+fields+"' -lco GEOMETRY=AS_WKT -f '"+type+"' "+outname+" "+tmpname

        #run the command
        if(v==1) {
            printf("%s\n",command)
            system(command)
        } else {
            syscall(command)
        }
    }


    define proj_geoshape(v,s_srs) {

        if($ARGC<2) {
            printf("\nThis function reprojects GeoShape-Struct\n\n")
            printf("$1=the davinci GeoShape-Struct\n")
            printf("$2=target projection argument (either a proj string or wkt, usually from a Geo-Struct)\n\n")
            printf("Options:\n")
            printf("\ts_srs=projection of the source (either a proj string or wkt, Default='+proj=longlat +a=3396190.0 +b=3396190.0 +units=m +no_defs')\n\n")
            printf("NOTE: This function requires $DV_GDAL_PATH\n")
            printf("and gdal version >=1.8\n\n")
            printf("c.edwards 4/9/13\n")
            return(null)
        }

        #setup the inputs
        shape=$1
        t_srs=$2
        if(HasValue(v)==0) v=0    
        if(HasValue(s_srs)==0) s_srs="+proj=longlat +a=3396190.0 +b=3396190.0 +units=m +no_defs"

        #set the working file name
        workingname=$TMPDIR+"/proj/gdal_shape.proj.csv" 
        syscall("mkdir -p "+dirname(workingname))

        #write the shapefile to disk and project simulatneously 
        #ogr2ogr combines gdal_translate/gdalwarp like options and we need it to
        #both translate the files and project the data

        write_geoshape(shape,workingname,s_srs=s_srs,t_srs=t_srs,type="CSV",force=1,v=v)

        #read the the data back in
        #note: we don't use gdal to translate csv if the source is already csv (messy result)
        out=read_geoshape(workingname,v=v)
        if(fexists(workingname)) syscall("rm "+workingname)

        return(out)
    }


    define proj_geocoord(inverse,t_srs,s_srs,v,opts) {
     
        if($ARGC<1) {
            printf("\nTransform one set of coordinates to another projection\n") 
            printf("The default behavior is to transform lat/lon to image coordinates in x/y pixels\n\n")
            printf("$1=array of points in the target projection (2xNx1)\n")
            printf("$2=Geo-Struct for which the mapping is desired\n\n")
            printf("Options:\n")
            printf("\tinverse=input units in the target, output units in the source (Default=1)\n")
            printf("\tt_srs=projection of the target (Default='+proj=longlat +a=3396190.0 +b=3396190.0 +units=m +no_defs')\n") 
            printf("\ts_srs=projection of the source (Default=Geo-Struct projection)\n\n")
            printf("\topts=additional ogr2ogr options (Default=\"\")\n")
            printf("\tNOTE: $2 and s_srs may not both be provided\n\n") 
            printf("Examples:\n")
            printf("#lat/lon input to map to pixel location in the GeoStruct\n")
            printf("\tout=proj_geocoord(15//15,GeoStruct)\n\n")
            printf("#lat/lon input to map to global meters in the eqc projection\n")
            printf("\tout=proj_geocoord(15//15,s_srs='+proj=latlong +units=deg',t_srs='+proj=eqc +units=m',inverse=0)\n\n")
            printf("NOTE: This function requires $DV_GDAL_PATH\n")
            printf("and gdal version >=1.8\n\n")
            printf("c.edwards 5/12/13\n\n")
            return(null)
        }

        #input handling
        latlon=$1
        if(HasValue(v)==0) v=0

        #handle other gdal options
        optstr=""
        if(HasValue(opts)!=0) {
            optstr=opts+" "
        }

        #error checking to make sure we don't break gdaltransform
        if($ARGC<2 && HasValue(s_srs)==0) {
            printf("Either a geostruct or a source s_srs must be supplied\n")
            return(null)
        }

        #if we have 2 arguments, the second has to be a geostruct
        #we then map the input units into xy in the image by default (most common usage
        if($ARGC==2) {
            geostruct=$2
            if(type(geostruct)!="STRUCT") {
                printf("$2 is not a valid GeoStruct\n") 
                return(null) 
            } else if (HasValue(get_struct(geostruct.anc,"wkt"))==0) {
                printf("$2 does not have a spatial reference system\n")
                return(null)
            }
        }

        #set the image mapping (-i =image coordinates, gdal default is projection coordinates)
        if(HasValue(inverse)==0) inverse=1
        invstr=""
        if(inverse==1) {
            invstr="-i "
        } else {
            invstr=""
        }

        #write the source geostruct or assign a s_srs
        s_srsstr=""
        if(HasValue(s_srs)==0) {
            #write the geostruct to disk...we really should have a way to do this better
            datafile=$TMPDIR+"/coordproj_data.tif"
            write_geotiff(geostruct,datafile,force=1,v=v)
            s_srsstr=datafile+" "
        } else {
            #parse the s_srs
            if(type(s_srs)=="STRING") {
                length=1
         } else if(type(s_srs)=="TEXT") {
             length=length(s_srs)
         }
        
            srsstr=""
            #cleanup the whitespace
            for(i=1;i<=length;i+=1) {
                srsstr+=trim_whitespace(s_srs[,i])
            }
            s_srsstr="-s_srs '"+srsstr+"' "
        }

        #write the latlon file to disk
        latlonfile=$TMPDIR+"/coordproj_input.ascii"
        latlonoutfile=$TMPDIR+"/coordproj_output.ascii"
        write(latlon,latlonfile,csv,separator=" ",force=1)

        #set the default t_srs 
        t_srsstr=""
        if(HasValue(t_srs)==0) {
            t_srsstr="-t_srs '+proj=longlat +a=3396190.0 +b=3396190.0 +units=m +no_defs' " 
        } else {

            #parse the t_srs
            if(type(t_srs)=="STRING") {
                length=1
            } else if(type(t_srs)=="TEXT") {
                length=length(t_srs)
            }
        
            srsstr=""
            #cleanup the whitespace
            for(i=1;i<=length;i+=1) {
                srsstr+=trim_whitespace(t_srs[,i])
            }
            t_srsstr="-t_srs '"+srsstr+"' "
        }

        #generate the gdaltransform command
        command=$DV_GDAL_PATH+"/gdaltransform "+optstr+invstr+t_srsstr+s_srsstr+"< "+latlonfile+" > "+latlonoutfile

        #run the command and read the transformed data.
        if(v==1) { 
            printf("%s\n",command)
            system(command)
        } else {
            syscall(command)
        }
     
        verbose=0
        out=ascii(latlonoutfile,delim=" ",format=double)[:2]
        if(v!=-1) verbose=3

        #return the output
        return(out)
    }



    define shape2georaster(a_srs_shape,a_srs_image,inverse,value,v,ignore,color,hsv,gradient,in_low,in_high,opts) {

        if($ARGC<2) {
            printf("\nOverlay a GeoShape-Struct on a Geo-Struct\n")
            printf("The GeoShape-Struct will be transformed into the Geo-Struct projection\n\n")
            printf("$1=GeoShape-Struct (in assumed latlong coordinates)\n")
            printf("$2=Geo-Struct (in any projection) \n\n")
            printf("Options:\n")
            printf("\ta_srs_shape=projection of the shapefile (Default='+proj=longlat +a=3396190.0 +b=3396190.0 +units=m +no_defs')\n")
            printf("\ta_srs_image=projection of the image (Default=Geo-Struct projection)\n")
            printf("\tinverse=leave everything but the shape (Useful for masking, Default=0)\n")
            printf("\tvalue=GeoShape-Struct element to map to each shape (Default=\"\")\n")
            printf("\tignore=override Geo-Struct .ignore value, if outside the data type then min(data) will be used\n")
            printf("\topts=additional gdal_rasterize options\n\n")
            printf("Post Processing Options:\n")  
            printf("\tcolor=translate the shape overlay into a color (Default=255/255/255)\n")
            printf("\tgradient=turn the value data into a gradient, maps to colors option in colorize() (Default=0)\n")
            printf("\tin_low=low data input value for gradient mapping (Default=min value w/ignore)\n")
            printf("\tin_high=high data input value for gradient mapping (Default=max value)\n")
            printf("\thsv=HSV composite overlay the output shape on the input (byte, single band) data (Default=0)\n\n")
            printf("NOTE: This function requires $DV_GDAL_PATH\n")
            printf("and gdal version >=1.8\n\n")
            printf("c.edwards 5/12/13\n\n")
            return(null)
        }


        shapestruct=$1
        geostruct=$2

        if(HasValue(v)==0) v=0    
        if(HasValue(a_srs_shape)==0) a_srs_shape="+proj=longlat +a=3396190.0 +b=3396190.0 +units=m +no_defs"
      if(HasValue(hsv)==0) hsv=0

        key=get_struct_key(shapestruct)
        key=strsub(key,"wkt","")

        otype="-ot Byte "
        attribstr=""

        if(HasValue(value)!=0) {
            test=grep(key,value)

            if(HasValue(test)=0) {
                printf("No match was found\n")
                printf("Please try another field name\n")
                return(null)
            }

            if(length(test)>1) {
                printf("More 1 match was found\n")
                printf("Enter a more specific field name\n")
                return(null)
            }

            element=key[,maxpos(key==grep(key,value)[,1])[2]]
            format=format(get_struct(obj=shapestruct,name=element))
            
            if(format=="byte") {
                otype="-ot Byte "
            } else if(format=="short") {
                otype="-ot Int16 "
            } else if(format=="int") {
                otype="-ot Int32 "
            } else if(format=="float") {
                otype="-ot Float32 "
            } else if(format=="double") {
                otype="-ot Float64 "
            } 

            if(format!="byte" && format!="short" && format!="int" && format!="float" && format!="double") {
                printf("Supported datatype was not found\n")
                printf("Reverting to mapping option\n")
                attribstr="-burn 255 "
            } else {
                attribstr="-a '"+element+"' "
            } 
        } else {
            attribstr="-burn 255 "
        }

        invstr=""
        if(HasValue(inverse)) invstr="-i "

        #handle other gdal options
        optstr=""
        if(HasValue(opts)!=0) {
            optstr=opts+" "
        }

        nodatastr=""
        if(HasValue(get_struct(geostruct,"ignore"))) {
            ign=geostruct.ignore
        }
        if(HasValue(ignore)!=0) {
            ign=ignore
        }    
        nodatastr=sprintf("-a_nodata '%.20g' ",ign)

        dim=dim(geostruct.data)
        sizestr=sprintf("-ts %i %i ",dim[1],dim[2])
        if(HasValue(get_struct(geostruct.anc,"lpo")) && HasValue(get_struct(geostruct.anc,"spo"))) { 
            sizestr+=sprintf("-te %f %f %f %f ",min(geostruct.anc.spo),min(geostruct.anc.lpo),max(geostruct.anc.spo),max(geostruct.anc.lpo))
        }

        #assign a target srs if set
        if(HasValue(a_srs_image)==0) a_srs_image=geostruct.anc.wkt
        a_srs_imagestr=""
        if(HasValue(a_srs_image)) {
            #parse the a_srs_image
            if(type(a_srs_image)=="STRING") {
                length=1
            } else if(type(a_srs_image)=="TEXT") {
                length=length(a_srs_image)
            }

            srsstr=""
            #cleanup the whitespace
            for(i=1;i<=length;i+=1) {
                srsstr+=trim_whitespace(a_srs_image[,i])
            }
            a_srs_imagestr="-a_srs '"+srsstr+"' "
        }

        #set the working file name
        layername="gdal_raster.proj"
        workingshape=$TMPDIR+"/raster/gdal_raster.proj.csv" 
        workingimage=$TMPDIR+"/raster/gdal_raster.proj.tif" 
        syscall("mkdir -p "+dirname(workingimage))

        #write the shapefile to disk and project simulatneously 
        #ogr2ogr combines gdal_translate/gdalwarp like options and we need it to
        #both translate the files and project the data
        write_geoshape(shapestruct,workingshape,s_srs=a_srs_shape,t_srs=a_srs_image,type="CSV",force=1,v=v)
        write_geotiff(geostruct,workingimage,force=1,v=v)
        
        #generate the gdaltransform command
        
        command=$DV_GDAL_PATH+"/gdal_rasterize -co \"BIGTIFF=NO\" "+sizestr+attribstr+invstr+otype+nodatastr+a_srs_imagestr+optstr+" -l "+layername+" -of GTiff "+workingshape+" "+workingimage 

        #run the command and read the transformed data.
        if(v==1) { 
            printf("%s\n",command)
            system(command)
        } else {
            syscall(command)
        }

        #read the data back in
        out=read_geo(workingimage)

        #set the data to a specified color
        if(HasValue(color)) {
            out.data=clone(out.data,z=3)
            out.data[where out.data!=ign]=translate(byte(color),x,z)
        }

        #set the data to a gradient
        if(HasValue(gradient)) {
            if(HasValue(in_low)==0) in_low=min(out.data,ignore=ign)
            if(HasValue(in_high)==0) in_high=max(out.data,ignore=ign)

            out.data=colorize(lstretch(out.data,in_low=in_low,in_high=in_high,ignore=ign),colors=gradient,ignore=0)
        }

        #overlay the new color data on the original map data
      if(hsv==1) {
          if(HasValue(color) || HasValue(gradient)) {
              if(type(geostruct.data)=="byte" && dim(geostruct.data)[3]==1) {
                  hsv=rgb2hsv(out.data)
                  hsv[,,3]=geostruct.data/255.
                  out.data=byte(hsv2rgb(hsv,maxval=255))
              } else {
                  printf("The input data must be both byte and a single band\n")
                  printf("returning original data\n\n")
              }
          } else {
              printf("If hsv option is selected, gradient or color must also be speicified\n")
              printf("returning original data\n\n")
          }
      }
      #return the data
      return(out)
    }


    define latlonDMS2dec(){

      if($ARGC==0) {
        printf("Take a formatted lat or lon string\n")
        printf("and translate it to decimal degrees\n\n")
        printf("$1=a lat/lon string formattted like \"###d##'##.####\"DIR\"\n\n")
        printf("c.edwards\n")
        return(null)
      }

      DMS_str=$1

      #get the degrees
      tmp=strsplit(DMS_str,delim="d")
      deg=atod(tmp[,1])
      DMS_str=tmp[,2]
      
      #get the minutes
      tmp=strsplit(DMS_str,delim="'")
      min=atod(tmp[,1])
      DMS_str=tmp[,2]

      #get the seconds
      tmp=strsplit(DMS_str,delim="\"")
      sec=atod(tmp[,1])
      dir=tmp[,2]
      
      if(dir=="W") {
        out=360-(deg+min/60.+sec/3600.)
      } else if(dir=="S") {
        out=-1*(deg+min/60.+sec/3600.)
      } else {
        out=deg+min/60.+sec/3600.
      }

      return(out)
    }



    define write_envi(force,v) {

        if($ARGC<2) {
            printf("\nThis function writes a basic or Geo-ENVI file and header\n")
            printf("The input data may be either a Geo-Struct or a data array\n\n")
            printf("$1=the davinci Geo-Struct or data array\n")
            printf("$2=the output filename\n\n")
            printf("Options:\n")
            printf("\tforce=force the overwrite of exiting data\n")
            printf("NOTE: This function requires $DV_GDAL_PATH\n")
            printf("and gdal version >=1.8\n\n")
            printf("WARNING: This function will output bad geo-referenced data\n")
            printf("if you change the data array size\n\n")
            printf("c.edwards 10/9/14\n")
            return(null)
        }

        input=$1
        outname=$2

        if(HasValue(force)==0) force=0
        if(HasValue(v)==0) v=1

        if(type(input)=="STRUCT") {
            write_geotiff(input,outname,force=force,envi=1)
        } else if (isnum(input)==1) {
            #translate DV datatype to ENVI hdr type
            dv_datatype=format(input)
            if(dv_datatype=="byte") {
                datatype=1
            } else if(dv_datatype=="short") {
                datatype=2
             } else if(dv_datatype=="int") {
                datatype=3
             } else if(dv_datatype=="float") {
                datatype=4
             } else if(dv_datatype=="double") {
                datatype=5
            }

            #write the raw data data
            if(v!=-1) printf("Writing %s: %ix%ix%i ENVI File\n",outname,dim(input)[1],dim(input)[2],dim(input)[3])
            write(input,outname,raw,force=force)

            #make and write the header
            envi_hdr=text(10)
            envi_hdr[,1]="ENVI"
            envi_hdr[,2]="description = { davinci write_envi() product }"
            envi_hdr[,3]="file type = ENVI standard"
            envi_hdr[,4]="header offset = 0"
            envi_hdr[,5]=sprintf("samples = %i",dim(input)[1])
            envi_hdr[,6]=sprintf("lines = %i",dim(input)[2])
            envi_hdr[,7]=sprintf("bands = %i",dim(input)[3])
            envi_hdr[,8]=sprintf("data type = %i",datatype)
            envi_hdr[,9]="byte order = 0"
            envi_hdr[,10]=sprintf("interleave = %s",org(input))
            if(v!=-1) printf("Writing %s.hdr: ENVI HDR File\n",outname)
            write(envi_hdr,outname+".hdr",ascii,force=force)

        } else {
            printf("Unsupported input data type\n")
            return(null)
        }
    }