#' Write ESRI shapefile out
#' \code{writeshape}
#' @param shp Spatial file
#' @param crs projection
#' @param file file path, without '.shp'.
#' @export
#' @examples
#' library(sp)
#' library(rgeos)
#' library(rgdal)
#' sp1 = readWKT("POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))")
#' raster::crs(sp1) =sp::CRS("+init=epsg:4326")
#' writeshape(sp1, file=file.path(tempdir(), 'sp1'))
#' sp2=readOGR(file.path(tempdir(), 'sp1.shp'))
#' plot(sp2)
writeshape <- function(shp, file=NULL, crs = raster::crs(shp)){
  msg='writeshape::'
  if(tolower(raster::extension(file)) == '.shp'){
    file = substr(file, 1, nchar(file)-4)
  }
  if(grepl(class(shp)[1],'SpatialPolygons' ) ){
    # shp = methods::as(shp, "SpatialPolygonsDataFrame")
    shp=sp::SpatialPolygonsDataFrame(shp, 
                                     data=data.frame('ID'=1:length(shp)),
                                     match.ID = FALSE)
  }else if ( grepl(class(shp)[1],'SpatialLines' )   ){
    # shp = methods::as(shp, "SpatialLinesDataFrame")
    shp=sp::SpatialLinesDataFrame(shp, data=data.frame('ID'=1:length(shp)),match.ID = FALSE)
  }
  if( is.null(file) ){
    # message(msg, 'No file exported')
  }else{
    path = dirname(file)
    fn = basename(file)
    if(!dir.exists(path)){
      dir.create(path, showWarnings = T, recursive = T)
    }
    raster::crs(shp) = crs;
    prj = sp::proj4string(shp)
    rgdal::writeOGR(obj=shp, driver = 'ESRI Shapefile',
                    layer=fn,
                    dsn=path, overwrite_layer = T)
    if( !is.na(crs) ){
      fn.prj = file;
      raster::extension(fn.prj) = '.prj'
      invisible(rgdal::showWKT(prj, file = fn.prj))
    }
    message(msg, file, ' is saved')
  }
}
#' Re-project coordinates betwen GCS and PCS
#' \code{ProjectCoordinate} 
#' @param  x 2-column matrix of coordinates.
#' @param  proj4string proj4string
#' @param  P2G if TRUE, a cartographic projection into lat/long, otherwise projects from lat/long into a cartographic projection.
#' @return Basic model infomation, figures and tables
#' @export
ProjectCoordinate <- function(x, proj4string, P2G=TRUE){
  # Transformed data
  x=as.matrix(x)
  y <- proj4::project(x, proj4string, inverse=P2G)
  if(P2G){
    colnames(y)=c('Lon','Lat')
  }else{
    colnames(y)=c('X','Y')
  }
  y
}
#' SpatialData to Raster
#' \code{sp2raster}
#' @param sp SpatialPolygon
#' @param mask Raster mask of mesh domain.
#' @param ngrids Number of grid along x direction.
#' @param resolution Resolution, defaul = NULL, resolution = extent / ngrids
#' @param field Index of field
#' @return Raster map
#' @export
sp2raster <- function (sp, mask = get('MASK', envir = .shud),
                       ngrids=200, 
                       resolution=NULL, field=1) {
  if( is.null(mask) ){
    ext <-  raster::extent (sp)
    xlim=ext[1:2]
    ylim=ext[3:4]
    if ( resolution<=0 || is.null(resolution)){
      dx=diff(xlim) / ngrids;
    }else{
      dx=resolution
    }
    r <- raster::raster(ext, res=dx)
  }else{
    r = mask
  }
  ## Rasterize the shapefile
  rr <-raster::rasterize(sp, r, field=field)
  return(rr)
}
#' Generate the raster mask of Mesh domain
#' \code{shud.mask}
#' @param pm \code{shud.mesh}
#' @param n Number of grid
#' @param rr Default mask in .shud environment
#' @param cellsize Resolution, defaul = NULL, resolution = extent / ngrids
#' @param proj Projection parameter
#' @return Raster map
#' @export
shud.mask  <- function (pm = readmesh(), proj=NULL,
                        rr = get('MASK', envir=.shud),
                        n=10000, cellsize=NULL){
  # mesh=readmesh(shp=TRUE); ngrids=100; resolution=0
  if(is.null(rr)){
    spm =sp.mesh2Shape(pm)
    sp0=rgeos::gUnaryUnion(spm)
    if(is.null(cellsize)){
      # grd <- as.data.frame(sp::spsample(spm, "regular", n=n))
      # grd <- as.data.frame(sp::spsample(spm, "regular", nsig=2, n=n))
      grd <- sp::makegrid(sp0, n = n)
    }else{
      # grd <- as.data.frame(sp::spsample(spm, "regular", cellsize = cellsize))
      grd <- sp::makegrid(sp0, cellsize = cellsize, pretty = FALSE)
    }
    names(grd)       <- c("X", "Y")
    sp::coordinates(grd) <- c("X", "Y")
    sp::gridded(grd)     <- TRUE  # Create SpatialPixel object
    sp::fullgrid(grd)    <- TRUE  # Create SpatialGrid object
    rr=raster::raster(grd); rr[]=1
    rr=raster::mask(rr, sp0)
    if(!is.null(proj)){
      raster::crs(rr) = proj
    }
    assign('MASK', rr, envir=.shud)
  }else{
    rr = rr
  }
  rr
}
#' SpatialData to Raster
#' \code{MeshData2Raster}
#' @param x vector or matrix, length/nrow is number of cells.
#' @param rmask mask of the mesh file
#' @param stack Whether export the stack, only when the x is a matrix, i.e. (Ntime x Ncell).
#' @param proj Projejction parameter
#' @param pm shud mesh
#' @param method method for interpolation, default = 'idw'
#' @param plot Whether plot the result.
#' @return Raster map
#' @export
MeshData2Raster <- function(x=getElevation(),
                            rmask=shud.mask(proj=proj), 
                            pm=readmesh(), proj=NULL,
                            stack=FALSE, method='ide',
                            plot =FALSE){
  
  if(stack){
    ret <- raster::stack(apply(x, 1, FUN = MeshData2Raster) )
  }else{
    if( is.matrix(x) | is.data.frame(x)){
      x = as.numeric(x[nrow(x),])
    }
    if(any(is.na(x)) ){
      x[is.na(x)] = 0
    }
    if (any(is.infinite(x))){
      x[is.infinite(x)] = 0
    }
    xy=getCentroid(pm=pm)[,2:3]
    
    if(grepl('idw', tolower(method))){
      val= data.frame(xy, x)
      colnames(val) = c('X', 'Y', 'Z')
      sp::coordinates(val) = c('X', 'Y')
      grd=methods::as(rmask, 'SpatialGrid')
      # if(grepl(method, 'idw')){
      # Interpolate the grid cells using a power value of 2 (idp=2.0)
      dat <- gstat::idw(Z ~ 1, val, newdata=grd, idp=2.0)
      r = raster::raster(dat)
    }
    if(grepl('linear', tolower(method))){
      xr = raster::rasterToPoints(rmask)
      ext=raster::extent(rmask);res=raster::res(rmask); hr = res/2
      r0=rmask; r0[]=1
      xyo=raster::rasterToPoints(r0)
      xx=interp::interp(x=xy[,1], y=xy[,2], z=x, xo=xyo[,1], yo=xyo[,2] )
      r = raster::setValues(rmask, as.numeric(xx$z))
    }
    if(grepl('ide', tolower(method))){
      tps <- fields::Tps(xy, x)
      # use model to predict values at all locations
      r <- raster::interpolate(rmask, tps)
    }
    ret <- raster::mask(r,rmask)
  }
  if(plot){
    raster::plot(ret)
  }
  if(!is.null(proj)){ raster::crs(ret) <- proj }
  return(ret)
}
#' Remove the holes in polygons
#' \code{removeholes}
#' @param sp SpatialPolygons or SpatialPolygonDataFrame
#' @return Raster map
#' @export
#' @examples
#' library(sp)
#' p.out = Polygon(cbind(c(4,4,6,7,4),c(5,3,2,5,5))  )
#' p.hole = Polygon(cbind(c(5,6,6,5,5),c(4,4,3,3,4) ), hole = TRUE)
#' sp <- SpatialPolygons(list(Polygons(list(p.out, p.hole), "1")))
#' s = removeholes(sp)
#' par(mfrow=c(1,2))
#' plot(sp)
#' plot(s)
removeholes <- function(sp){
  x = sp
  nx = length(x)
  # vn = rownames(x@data)
  rl = list()
  for(i in 1:nx){
    spg = x@polygons[[i]]@Polygons
    npg = length(spg)
    ypg = list()
    k=1
    for(j in 1:npg){
      if(spg[[j]]@hole){
      }else{
        ypg[[k]] = spg[[j]]
        k = k+1
      }
    }
    rl[[i]] = sp::Polygons(ypg, ID=i)
  }
  ysp = sp::SpatialPolygons(rl)
  # ret = SpatialPolygonsDataFrame(ysp, data=x@data)
  ret = ysp
  if( !is.na(raster::crs(x)) & ! is.null(raster::crs(x)) ){
    raster::crs(ret) = raster::crs(x)
  }
  return(ret)
}
#' Generatue fishnet
#' \code{fishnet} Generate fishnet by the coordinates
#' @param xx  x coordinates
#' @param yy  y coordinates
#' @param crs projections parameters, defaul = epsg:4326
#' @param type option = 'polygon', 'points', 'line'
#' @return spatildata (.shp)
#' @export
#' @examples
#' library(raster)
#' ext=c(0, 8, 2, 10)
#' dx = 2; dy = 4
#' xx=seq(ext[1], ext[2], by=dx)
#' yy=seq(ext[3], ext[4], by=dy)
#' sp1 =fishnet(xx=ext[1:2], yy=ext[3:4])
#' sp2 =fishnet(xx=xx + .5 * dx, yy=yy + 0.5 * dy)
#' sp3 =fishnet(xx=xx, yy=yy, type = 'point')
#' plot(sp1, axes=TRUE, xlim=c(-1, 1)*dx +ext[1:2], ylim=c(-1, 1)*dy + ext[3:4])
#' plot(sp2, axes=TRUE, add=TRUE, border=2)
#' plot(sp3, axes=TRUE, add=TRUE, col=3, pch=20)
#' grid()
fishnet <- function(xx, yy,
                    crs=sp::CRS("+init=epsg:4326"),
                    type='polygon'){
  nx = length(xx)
  ny = length(yy)
  if(grepl('line', tolower(type)) ){
    ymin = min(yy); ymax = max(yy)
    xmin = min(xx); xmax = max(xx)
    vline=cbind(xx, ymin, xx, ymax)
    hline =  cbind(xmin, yy, xmax, yy)
    mat = rbind(vline, hline)
    str=paste(paste('(', mat[,1], mat[,2],',', mat[,3], mat[,4], ')'), collapse = ',')
    spl=rgeos::readWKT(paste('MULTILINESTRING(', str, ')'))
    df = as.data.frame(mat)
    colnames(df) = c('x1', 'y1', 'x2','y2')
    spdf=sp::SpatialLinesDataFrame(spl, data = df)
    ret = spdf
  }
  if(grepl('polygon', tolower(type)) ){
    xy=expand.grid(xx,yy)
    xm = matrix(xy[,1], nx,ny)
    ym = matrix(xy[,2], nx, ny)
    xloc=abind::abind(as.matrix(xm[-nx, -ny]), as.matrix(xm[-nx, -1]), as.matrix(xm[-1, -1]),
                      as.matrix(xm[-1, -ny]), as.matrix(xm[-nx, -ny]), along=3)
    yloc=abind::abind(as.matrix(ym[-nx, -ny]), as.matrix(ym[-nx, -1]), as.matrix(ym[-1, -1]),
                      as.matrix(ym[-1, -ny]), as.matrix(ym[-nx, -ny]), along=3)
    
    # df=as.data.frame(matrix(0, nrow=(nx-1)*(ny-1), 6))
    df=data.frame(as.numeric(apply(xloc, 1:2, min)),
                  as.numeric(apply(xloc, 1:2, max)),
                  as.numeric(apply(yloc, 1:2, min)),
                  as.numeric(apply(yloc, 1:2, max)))
    df = data.frame(df, rowMeans(df[,1:2]), rowMeans(df[,1:2+2]) )
    colnames(df) = c('xmin','xmax','ymin', 'ymax','xcenter','ycenter')
    str=paste('GEOMETRYCOLLECTION(',
              paste(paste('POLYGON((',
                          paste(xm[-nx, -ny], ym[-nx, -ny], ',' ),
                          paste(xm[-nx, -1],  ym[-nx, -1], ','),
                          paste(xm[-1, -1],   ym[-1, -1], ','),
                          paste(xm[-1, -ny],  ym[-1, -ny], ','),
                          paste(xm[-nx, -ny], ym[-nx, -ny], '' ), '))' )
                    , collapse =','),
              ')' )
    # str=paste('MULTIPOLYGON(', paste(xt, collapse = ', '), ')')
    SRL = rgeos::readWKT(str)
    # x1 = x0@polygons[[1]]@Polygons
    # SRL =lapply(1:length(x1),  function(x, i) {Polygons(list(x[[i]]), ID=i)},  x=x1 )
    ret = sp::SpatialPolygonsDataFrame( Sr=SRL, data=df, match.ID = TRUE)
  }
  if(grepl('point', tolower(type)) ){
    xm = expand.grid(xx, yy)
    df = data.frame('X' = xm[, 1], 'Y' = xm[,2])
    ret = sp::SpatialPointsDataFrame(coords = df, data=df, match.ID = TRUE)
  }
  raster::crs(ret) = crs
  return(ret)
}
#' Add holes into Polygons
#' \code{AddHoleToPolygon}
#' @param poly SpatialPolygons
#' @param hole Hole Polygon
#' @export
AddHoleToPolygon <-function(poly,hole){
  # https://stackoverflow.com/questions/29624895/how-to-add-a-hole-to-a-polygon-within-a-spatialpolygonsdataframe
  # invert the coordinates for Polygons to flag it as a hole
  coordsHole <-  hole@polygons[[1]]@Polygons[[1]]@coords
  newHole <- sp::Polygon(coordsHole,hole=TRUE)
  
  # punch the hole in the main poly
  listPol <- poly@polygons[[1]]@Polygons
  listPol[[length(listPol)+1]] <- newHole
  punch <-sp::Polygons(listPol,poly@polygons[[1]]@ID)
  
  # make the polygon a SpatialPolygonsDataFrame as the entry
  new <- sp::SpatialPolygons(list(punch),proj4string=poly@proj4string)
  new <- sp::SpatialPolygonsDataFrame(new,data=as(poly,"data.frame"))
  return(new)
}
#' Cut sptialLines with threshold.
#' \code{sp.CutSptialLines}
#' @param sl SpatialLines or SpatialLineDataFrame
#' @param tol Tolerence. If the length of segment is larger than tolerance, cut the segment until the maximum segment is shorter than tolerance.
#' @export
#' @examples
#' library(rSHUD)
#' library(sp)
#' x=1:1000/100
#' l1 = Lines(Line(cbind(x, sin(x)) ), ID='a' )
#' sl = SpatialLines( list(l1) )
#' tol1=5;
#' tol2 =2
#' sl1 = sp.CutSptialLines(sl, tol1)
#' sl2 = sp.CutSptialLines(sl, tol2)
#' par(mfrow=c(1,2))
#' plot(sl1, col=1:length(sl1));title(paste0('Tol=', tol1))
#' plot(sl2, col=1:length(sl2));title(paste0('Tol=', tol2))
#'
#' data(sh)
#' riv=sh$riv
#' x = sp.CutSptialLines(riv, tol=5)
#' par(mfrow=c(2,1))
#' plot(riv, col=1:length(riv), lwd=3);
#'
#' plot(riv, col='gray', lwd=3);
#' plot(add=TRUE, x, col=1:length(x))
sp.CutSptialLines <- function(sl, tol){
  msg='sp.CutSptialLines::'
  ll = rgeos::gLength(sl, byid = TRUE)
  if(all(ll < tol) ){
    ret = sl
  }else{
    nsp = length(sl)
    xsl = list(); ik=1
    for(i in 1:nsp){
      sx = sl[i, ]
      pxy = extractCoords(sx,unique = TRUE)
      np = nrow(pxy)
      dacc = cumsum( sp::LineLength(pxy, sum = FALSE))
      # dacc =getDist(pxy)
      tol = max(c(tol, min(dacc) ) )
      len= rgeos::gLength(sx)
      if(len > tol){
        nsplit = ceiling(len / tol)
      }else{
        nsplit = 1
      }
      dd = len / nsplit
      v0 = 1  # Vetex 0, Vetex 1
      message(msg, i, '/', nsp, '\t', nsplit, '\t', round(dd, 2) )
      for(k in 1:nsplit){
        if(v0 >=np){
          break
        }
        # message(msg, '\t', k, '/', nsplit)
        dk = dd * k
        v1 = order(abs(dacc - dk), decreasing = FALSE)[1] + 1
        if(v1 + 1>np){
          v1 = np
        }
        message(msg, v0,'\t', v1)
        if(v0 == v1){
          next;
        }
        # plot(sl[i, ]);points(pxy); points(pxy[c(v0, v1), ], pch=2, col=2)
        xsl[[ik]]= sp::Lines(sp::Line( pxy[c(v0:v1), ]), ID=ik)
        ik=ik+1
        # points(pxy[v0:v1,], col=k)
        v0=v1
      }
    }
    nsl = length(xsl)
    tmp = sp::SpatialLines(xsl, proj4string = raster::crs(sl))
    ilen = rgeos::gLength(tmp, byid=TRUE)
    att=data.frame('INDEX'=1:length(tmp), 'Length'=ilen)
    ret = sp::SpatialLinesDataFrame(tmp, data = att)
  }
  return(ret)
}
#' Extract values on Raster map. The line is a straight line between (0,1). 
#' \code{extractRaster}
#' @param r Raster
#' @param xy coordinates of the line, dim=(Npoints, 2); x and y must be in [0, 1]
#' @param ext extension of value xy.
#' @param plot Whether plot result.
#' @importFrom grDevices dev.off graphics.off png rgb topo.colors
#' @importFrom graphics grid hist lines par plot points
#' @importFrom methods as
#' @importFrom stats dist rnorm time
#' @importFrom utils read.table
#' @export
#' @examples
#' library(raster)
# r <- raster(ncol=36, nrow=18)
# r[] <- 1:ncell(r)
# extractRaster(r)
extractRaster<-function(r, xy=NULL, ext = raster::extent(r), plot=T){
  if(is.null(xy)){
    ndim = dim(r)
    x=0:ndim[2] / ndim[2]
    y = rep(0.5, length(x))
    xy = cbind(x,y)
  }
  x = ext[1] + xy[,1] * (ext[2]- ext[1] )
  y = ext[3] + xy[,2] * (ext[4]- ext[3] )
  if(plot){
    raster::plot(r);
    points(x, y, col=2)
    nx=length(x)
    points(x,y)
    graphics::arrows(x[1], y[1], x[nx], y[nx], lty=3, lwd=1.5, col=2)
    # lines(x,y, lwd=1.5, col=2, lty=2)
  }
  v = raster::extract(r, cbind(x,y))
  ret = cbind('x'=x,'y'=y,'z'=v)
  return(ret)
}
#' Simplify SpatialData.
#' @param x SpatialData
#' @return Simplified SpatialData
#' @export
SimpleSpatial <-function(x){
  # n1=length(x@polygons)
  # nj=unlist(lapply(1:n1, function(i){ length(x@polygons[[i]]@Polygons) } ))
  # x@polygons[[1]]@Polygons[[1]]@coords
  msg='SimpleSpatial'
  ni = length(x@polygons)
  k=1
  sl=list()
  for(i in 1:ni){
    nj = length(x@polygons[[1]]@Polygons)
    for(j in 1:nj){
      cd = x@polygons[[i]]@Polygons[[j]]@coords
      np=nrow(cd)
      message(msg, i,'-',j ,'\t', np)
      sl[[k]] = paste('POLYGON((', paste( paste(cd[,1], cd[,2]), collapse = ',' ), '))')
      if(k==1){
        str = sl[[k]]
      }else{
        str = paste(str, ',', sl[[k]] )
      }
      k=k+1
    }
  }
  r=rgeos::readWKT(paste('GEOMETRYCOLLECTION(', str, ')'))
}
#' Find the points in distance less than tol.
#' \code{PointInDistance}
#' @param pt 2-column coordinates (x,y).
#' @param tol Tolerance
#' @return Index of points that within tol
#' @export
PointInDistance <- function(pt, tol){
  msg='PointInDistance'
  dm = as.matrix(stats::dist(pt, diag  = TRUE))
  dm[dm==0]=NA
  # View(dm)
  dmin=apply(dm, 1, min, na.rm=T)
  id=which(dmin < 100)
  id1=id2=NULL
  tmp1=tmp=dmin[id]
  i=2
  for(i in 1:length(id)){
    if(id[i] %in% id2){next }
    id1 = c(id1, i); id1
    tmp1[id1] = NA; tmp1
    id[which(tmp1 %in% tmp[id1])]
    id2=unique(c(id2,  id[which(tmp1 %in% tmp[id1])]))
    id2
    tmp1=tmp
  }
  cbind('P1'=id[id1], P2=id2)
}
#' Conver the MULTIPOLYGONS to SINGLEPOLYGONS.
#' @param x the spatialpolygon*
#' @param id Index of the sorted (decreasing) polygons to return. default = 0;
#' @export
SinglePolygon <- function(x, id=0){
  n1 = length(x)
  y1 = list()
  y2 = list()
  k=1
  for(i in 1:n1){
    message('level 1:', i, '/', n1)
    x1 = x@polygons[[i]]
    
    n2=length(x1@Polygons)
    for(j in 1:n2){
      message('level 2:', j, '/', n2)
      x2 = x1@Polygons[[j]]
      y1[[k]] = Polygons( list(x2), ID=k)
      k=k+1
    }
  }
  
  y=sp::SpatialPolygonsDataFrame(SpatialPolygons(y1), data=data.frame('ID'=2:k-1))
  
  if(id < 1){
    return(y)
  }else{
    ia=rgeos::gArea(y, byid = TRUE)
    id=order(ia, decreasing = TRUE)[1]
    return(y[id,])
    
  }
}
#' Remove the duplicated lines, which means the FROM and TO points are identical.
#' \code{rmDuplicatedLines}
#' @param x ShapeLine*
#' @param ... More options in duplicated()
#' @return ShapeLine* without duplicated lines.
#' @export
rmDuplicatedLines <- function(x, ...){
  # x=spi.riv
  cd = extractCoords(x)
  # dim(cd)
  ft = FromToNode(x, cd)
  id=which(duplicated(ft[, -1], MARGIN = 1, ...))
  if(length(id)>0){
    r =x[-id,]
  }else{
    r = x
  }
  return(r)
}
#' Generate Thiesson Polygons from a point data
#' \code{voronoipolygons}
#' @param x ShapePoints* in PCS
#' @param pts Coordinates (x,y) of the points
#' @param rw extent
#' @param crs projection parameters
#' @return ShapePolygon*
#' @export
#' @examples 
#' library(rgeos)
#' library(rSHUD)
#' n=10
#' xx = rnorm(n)
#' yy = rnorm(n)
#' str = paste('MULTIPOINT(', paste(paste('(', xx, yy, ')'), collapse = ','), ')')
#' x=readWKT(str)
#' vx = voronoipolygons(x)
#' raster::plot(vx, axes=TRUE)
#' raster::plot(add=TRUE, x, col=2)
#' #' ====END====
#' 
#' x=1:5
#' y=1:5
#' xy=expand.grid(x,y)
#' vx=voronoipolygons(pts=xy)
#' plot(vx, axes=TRUE)
#' points(xy)
#' #' ====END====
#' 
#' library(rgdal)
#' library(raster)
#' library(rgeos)
#' n=10
#' xx = rnorm(n)
#' yy = rnorm(n)
#' str = paste('MULTIPOINT(', paste(paste('(', xx, yy, ')'), collapse = ','), ')')
#' x=readWKT(str)
#' y=readWKT(paste('MULTIPOINT(', paste(paste('(', xx+2, yy+2, ')'), collapse = ','), ')'))
#' e1 = extent(y)
#' e2 = extent(x)
#' rw = c(min(e1[1], e2[1]),
#'        max(e1[2], e2[2]),
#'        min(e1[3], e2[3]),
#'        max(e1[4], e2[4]) ) + c(-1, 1, -1, 1)
#' vx=voronoipolygons(x=x, rw=rw)
#' plot(vx); plot(add=TRUE, x, col=2); plot(add=TRUE, y, col=3)
voronoipolygons = function(x, pts = x@coords, rw=NULL, crs=NULL) {
  z = deldir::deldir(pts[,1], pts[,2], rw=rw)
  w = deldir::tile.list(z)
  polys = vector(mode='list', length=length(w))
  for (i in seq(along=polys)) {
    pcrds = cbind(w[[i]]$x, w[[i]]$y)
    pcrds = rbind(pcrds, pcrds[1,])
    polys[[i]] = sp::Polygons(list(sp::Polygon(pcrds)), ID=as.character(i))
  }
  SP = sp::SpatialPolygons(polys)
  voronoi = sp::SpatialPolygonsDataFrame(SP, 
                                         data=data.frame(x=pts[,1], 
                                                         y=pts[,2], row.names=sapply(slot(SP, 'polygons'), 
                                                                                     function(x) slot(x, 'ID'))))
  if(!is.null(crs)){
    raster::crs(voronoi) = crs;
  }
  return(voronoi)
}
#' Generate the coverage map for forcing sites.
#' \code{ForcingCoverage}
#' @param sp.meteoSite ShapePoints* in PCS
#' @param pcs Projected Coordinate System
#' @param gcs Geographic Coordinate System
#' @param dem DEM raster
#' @param wbd watershed boundary
#' @param enlarge enlarge factor for the boundary.
#' @return ShapePolygon*
#' @export
ForcingCoverage <- function(sp.meteoSite=NULL, filenames=paste0(sp.meteoSite@data$ID, '.csv'),
                            pcs, gcs=sp::CRS('+init=epsg:4326'), 
                            dem, wbd, enlarge = 10000
                            ){
  if( is.null(sp.meteoSite) ){
    sp.meteoSite = rgeos::gCentroid(wbd)
  }
  x.pcs = sp::spTransform(sp.meteoSite, pcs)
  x.gcs = sp::spTransform(sp.meteoSite, gcs)
  
  ll = sp::coordinates(x.gcs)
  xy = sp::coordinates(x.pcs)
  z = raster::extract(dem, x.pcs)
  
  att = data.frame(1:length(sp.meteoSite), ll, xy, z, filenames)
  colnames(att) = c('ID', 'Lon', 'Lat', 'X', 'Y','Z', 'Filename')
  
  e1 = raster::extent(wbd)
  e2 = raster::extent(x.pcs)
  rw = c(min(e1[1], e2[1]), 
         max(e1[2], e2[2]),
         min(e1[3], e2[3]),
         max(e1[4], e2[4]) ) 
  if(is.null(enlarge)){
    enlarge = min(diff(rw[1:2]), diff(rw[3:4])) * 0.02
  }
  rw = rw + c(-1, 1, -1, 1) * enlarge
  if(length(x.pcs)<2){
    sp.forc = fishnet(xx = rw[1:2],yy = rw[3:4], crs=pcs)
  }else{
    sp.forc=voronoipolygons(x=x.pcs, rw=rw, crs=pcs)
  }
  att[is.na(att)] = -9999
  sp.forc@data = att
  return(sp.forc)
}
#' Find the subset of a extent in a grid.
#' \code{grid.subset}
#' @param ext txtent of the grid
#' @param res resolution of the grid
#' @param ext.sub the extent of subset
#' @param x x coordinates of the grids
#' @param y y coordinates of the grids
#' @return list, list(xid, yid, x, y)
#' @export
#' @examples 
grid.subset <- function(ext, res,
                        ext.sub,
                        dx =matrix(res, 2,1)[1],
                        dy =matrix(res, 2,1)[2],
                        x = seq(ext[1]+dx/2, ext[2]-dx/2, by=dx),
                        y = seq(ext[3]+dy/2, ext[4]-dy/2, by=dy)
                        ){
  xmin = min(x - dx/2); xmax = max(x + dx/2)
  ymin = min(y - dy/2); ymax = max(y + dy/2)
  # ext= c(min(x), max(x), min(y), max(y))
  if(ext.sub[1] < xmin | ext.sub[2] > xmax | ext.sub[3] < ymin | ext.sub[4] > ymax){
    warning(paste('Extent required is larger than the boundbox of dataset'))
    message(paste(ext.sub, collaps=','))
    message(paste(c(xmin,xmax,ymin, ymax), collaps=','))
  }
  xid = min(which(abs(x  - ext.sub[1]) <= dx/2)):max(which(abs(x  - ext.sub[2]) <= dx/2))
  yid = min(which(abs(y  - ext.sub[3]) <= dy/2)):max(which(abs(y  - ext.sub[4]) <= dy/2))
  nx = length(xid); ny = length(yid)
  x.cord = x[xid]; y.cord = y[yid]
  rt = list('xid' = xid,
            'yid' = yid,
            'x'=x.cord,
            'y'=y.cord)
  return(rt)
}
#' Generate a shapefile from coordinates.
#' \code{xy2shp}
#' @param xy matrix
#' @param df attribute table
#' @param crs projection parameters
#' @param shape Shape of the result in points, lines or polygons
#' @return SpatialPointsDataFrame, SpatialLinesDataFrame, or SpatialPolygonsDataFrame
#' @export
#' @examples 
#' library(raster)
#' xy=list(cbind(c(0, 2, 1), c(0, 0, 2)),  cbind(c(0, 2, 1), c(0, 0, 2))+2)
#' sp1 = xy2shp(xy=xy, shape = 'polygon')
#' raster::plot(sp1, axes=TRUE, col='gray')
#' 
#' sp2 = xy2shp(xy=xy, shape = 'lines')
#' raster::plot(sp2, add=TRUE, lty=2, lwd=3,col='red')
#' sp3 = xy2shp(xy=xy, shape = 'POINTS')
#' raster::plot(sp3, add=TRUE, pch=1, cex=2)
#' 
xy2shp <- function(xy, df=NULL, crs=NULL, shape='points'){
  if(grepl('point', tolower(shape))){
    if(!is.list(xy)){
      xy = list(xy)
    }
    xy = do.call(rbind, xy)
    if(is.null(df)){
      df = data.frame('ID'= 1:nrow(xy))
    }
    s1= paste0('POINT(', paste(xy[,1], xy[,2]), ')' )
    s2= paste('GEOMETRYCOLLECTION(', paste(s1, collapse = ','), ')')
    sp.xy=rgeos::readWKT(s2)
    spd=sp::SpatialPointsDataFrame(sp.xy, data=df, match.ID = FALSE)
  }else if(grepl('line', tolower(shape))){
    if(!is.list(xy)){
      xy = list(xy)
    }
    if(is.null(df)){
      df = data.frame('ID'= 1:length(xy))
    }
    nl = length(xy)
    fx <- function(x){
      # x=rbind(x, x[1, ])
      paste0('(', paste(paste(x[,1], x[,2]), collapse = ','), ')')
    }
    s1 = paste0('LINESTRING', unlist(lapply(xy, FUN = fx)), '')
    s2= paste('GEOMETRYCOLLECTION(', paste(s1, collapse = ','), ')')
    sp.xy=rgeos::readWKT(s2)
    
    spd=sp::SpatialLinesDataFrame(sp.xy, data=df, match.ID = FALSE)
  }else if(grepl('polygon', tolower(shape))){
    if(!is.list(xy)){
      xy = list(xy)
    }
    if(is.null(df)){
      df = data.frame('ID'= 1:length(xy))
    }
    nl = length(xy)
    fx <- function(x){
      x=rbind(x, x[1, ])
      paste0('(', paste(paste(x[,1], x[,2]), collapse = ','), ')')
    }
    s1 = paste0('POLYGON(', unlist(lapply(xy, FUN = fx)), ')')
    s2= paste('GEOMETRYCOLLECTION(', paste(s1, collapse = ','), ')')
    sp.xy=rgeos::readWKT(s2)
    
    spd=sp::SpatialPolygonsDataFrame(sp.xy, data=df, match.ID = FALSE)
  }
  if(!is.null(crs)){
    raster::crs(spd)=crs
  }
  return(spd)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.