Skip to main content
added 93 characters in body
Source Link
Jeffrey Evans
  • 32k
  • 2
  • 48
  • 97

Here is an R function that implements the Alpha Hull model. The output is an sp polygon object. Please see the example in the header. It requires the sp, alphahull and maptools packages.

**Update (01-15-2018) There have been numerous changes to the resulting objects produced by the alphahull package. As such, I needed to rewrite the function. I added a convexHull function to the spatialEco package. However, due to licensing restrictions in the alphahull package this function is only available in the development version on GitHub. The development version can be installed using:

library(devtools)
install_github("jeffreyevans/spatialEco")

Here is an example of the functions usage

library(sp)
library(spatialEco)
data(meuse)
 coordinates(meuse) = ~x+y
a <- convexHull(meuse, alpha=100000)
  plot(a)
    points(meuse, pch=19)

Convert the resulting SpatialLinesDataFrame to SpatialPolygonsDataFrame

library(sf)
a <- sf::st_as_sf(a) 
a <- sf::st_polygonize(a)
class( a <- as(a, "Spatial") )
  plot(a)

Test multiple alpha values

par(mfcol=c(2,2))
   for (a in c(500, 1500, 5000, 100000)) {
   ch <- convexHull(meuse, alpha = a)
     plot(ch)
      points(meuse, pch=19)
        title( paste0("alpha=", a))      
   }

various ahull alpha parameter(s)

Here is an R function that implements the Alpha Hull model. The output is an sp polygon object. Please see the example in the header. It requires the sp, alphahull and maptools packages.

**Update (01-15-2018) There have been numerous changes to the resulting objects produced by the alphahull package. As such, I needed to rewrite the function. I added a convexHull function to the spatialEco package. However, due to licensing restrictions in the alphahull package this function is only available in the development version on GitHub. The development version can be installed using:

library(devtools)
install_github("jeffreyevans/spatialEco")

Here is an example of the functions usage

library(sp)
library(spatialEco)
data(meuse)
 coordinates(meuse) = ~x+y
a <- convexHull(meuse, alpha=100000)
  plot(a)
    points(meuse, pch=19)

Convert the resulting SpatialLinesDataFrame to SpatialPolygonsDataFrame

library(sf)
a <- sf::st_as_sf(a) 
a <- sf::st_polygonize(a)
class( a <- as(a, "Spatial") )
  plot(a)

Test multiple alpha values

par(mfcol=c(2,2))
   for (a in c(500, 1500, 5000, 100000)) {
   ch <- convexHull(meuse, alpha = a)
     plot(ch)
      points(meuse, pch=19)
        title( paste0("alpha=", a))      
   }

Here is an R function that implements the Alpha Hull model. The output is an sp polygon object. Please see the example in the header. It requires the sp, alphahull and maptools packages.

**Update (01-15-2018) There have been numerous changes to the resulting objects produced by the alphahull package. As such, I needed to rewrite the function. I added a convexHull function to the spatialEco package. However, due to licensing restrictions in the alphahull package this function is only available in the development version on GitHub. The development version can be installed using:

library(devtools)
install_github("jeffreyevans/spatialEco")

Here is an example of the functions usage

library(sp)
library(spatialEco)
data(meuse)
 coordinates(meuse) = ~x+y
a <- convexHull(meuse, alpha=100000)
  plot(a)
    points(meuse, pch=19)

Convert the resulting SpatialLinesDataFrame to SpatialPolygonsDataFrame

library(sf)
a <- sf::st_as_sf(a) 
a <- sf::st_polygonize(a)
class( a <- as(a, "Spatial") )
  plot(a)

Test multiple alpha values

par(mfcol=c(2,2))
   for (a in c(500, 1500, 5000, 100000)) {
   ch <- convexHull(meuse, alpha = a)
     plot(ch)
      points(meuse, pch=19)
        title( paste0("alpha=", a))      
   }

various ahull alpha parameter(s)

Update to provided code
Source Link
Jeffrey Evans
  • 32k
  • 2
  • 48
  • 97

**Update (01-15-2018) There have been numerous changes to the resulting objects produced by the alphahull package. As such, I needed to rewrite the function. I added a convexHull function to the spatialEco package. However, due to licensing restrictions in the alphahull package this function is only available in the development version on GitHub. The development version can be installed using:

######################################################################################
# PROGRAM: ConvexHull 
# USE: CREATE CONVEX HULL USING THE Pateiro-Lopez ALPHAHULL MODEL  
# REQUIRES: sp, alphahull, maptools 
#                                                                                                                                                                                                     
# ARGUMENTS:  
#       x          sp Points CLASS OBJECT                       
#       alpha      CONVEX HULL ALPHA VALUE (SEE ?alphahull)
#       increment  DEFAULT 360    
#       rnd        DEFAULT 2
# 
# VALUE:  
#      A sp SpatialPolygonsDataFrame OBJECT         
#
# NOTES:
#    THIS METHOD PROVIDES FLEXIBILITY OVER TRADITIONAL CONVEX FUNCTIONS. YOU CAN 
#      ADJUST THE ALPHA PARAMETER TO RELAX OR INCREASE TENSION BETWEEN EDGE-BOUNDARY
#      POINTS TO CREATE MORE OF AN EXACT FIT OF THE ENVELOPE library(SEE EXAMPLEdevtools).
#
# REFERENCES:
#    Pateiro-López & Rodríguez-Casal install_github(2009"jeffreyevans/spatialEco") Generalizing the Convex Hull of a Sample: 
#      The R Package alphahull. Journal of Statistical Software 34

Here is an example of the functions usage

library(5sp):1-28 
#      http://www.jstatsoft.org/v34/i05/paper
#                                                                       
# EXAMPLES: 
#    requirelibrary(spspatialEco)
#    data(meuse)
#    coordinates(meuse) = ~x+y
#    a <- ConvexHullconvexHull(meuse, alpha=100000)
#      plot(a)
#        points(meuse, pch=19)
#    # TEST MULTIPLE alpha VALUES
#    a=c(1000, 100000)
#     par(mfcol=c

Convert the resulting SpatialLinesDataFrame to SpatialPolygonsDataFrame

library(1,2)sf)
#       for (alpha in a) {
#       ch <- ConvexHull(meuse, alpha=alpha)
#         plot(ch)
#          points(meuse, pch=19) 
#       }
#                                                                                   
# CONTACTsf:
#     Jeffrey S. Evans
#     Senior Landscape Ecologist  
#     The Nature Conservancy
#     Central Science/DbyD
#     Affiliate Assistant Professor
#     Environment and Natural Resources
#     University of Wyoming
#     Laramie, WY 82070 
#     [email protected]
#     (970) 672-6766
######################################################################################  
ConvexHull <- function(x, alpha=250000, increment=360, rnd=2)   {
    if (!require (sp)) stop("sp PACKAGE MISSING")
      if (!require (alphahull)) stop("sp PACKAGE MISSING")
        if (!require(maptools)) stop("maptools PACKAGE MISSING")
    if (!inherits(x, "SpatialPointsDataFrame") |  !inherits(x, "SpatialPoints") ) 
      stop(deparse(substitute(x)), " MUST BE A sp Points OBJECT")
        x.coords <- coordinates(x)    
    ahull2sp <- function(x, increment=360, rnd=10, proj4string=CRS(as.character(NA))){
      if (class(x) != "ahull")
        stop("x needs to be an ahull class object")
      xdf <- as.data.frame(x$arcs)
      xdf <- subset(xdf,xdf$r > 0)
      res <- NULL
      if (nrow(xdf) > 0){
        linesj <- list()
        prevx<-NULL
        prevy<-NULL
        j<-1
        for(i in 1:nrow(xdf)){
          rowi <- xdf[i,]
          v <- c(rowi$v.x, rowi$v.y)
          theta <- rowi$theta
          r <- rowi$r
          cc <- c(rowi$c1, rowi$c2)
          ipoints <- 2 + round(increment * (rowi$theta / 2),0)
          angles <- anglesArc(v, theta)
          seqang <- seqst_as_sf(angles[1], angles[2], length = ipointsa)
          x <- round(cc[1] + r * cos(seqang),rnd)
          ya <- round(cc[2] + r * sin(seqang),rnd)
          if (is.null(prevx)){
            prevx<-x
            prevy<-y
          } else if (x[1] == round(prevx[length(prevx)],rnd) && y[1] == round(prevy[length(prevy)],rnd)){
              if (i == nrow(xdf)){
                prevx<-append(prevx,x[2sf:ipoints])
                prevy<-append(prevy,y[2:ipoints])
                prevx[length(prevx)]<-prevx[1]
                prevy[length(prevy)]<-prevy[1]
                coordsj<-cbind(prevx,prevy)
                colnamesst_polygonize(coordsja)<-NULL
                linej <- Lineclass(coordsj)
                linesj[[j]]a <- Lines(linej, ID = as.character(j))
              } else {
                prevx<-append(prevx,x[2:ipoints])
                prevy<-append(prevy,y[2:ipoints])
              }
            } else {
              prevx[length(prevx)]<-prevx[1]
              prevy[length(prevy)]<-prevy[1]
              coordsj<-cbind(prevxa,prevy)
              colnames(coordsj"Spatial")<-NULL
              linej <- Line(coordsj)
              linesj[[j]] <- Lines(linej, ID = as.characterplot(j)a)
              j<-j+1
              prevx<-NULL
              prevy<-NULL
            }
        }
        lspl <- SpatialLines

Test multiple alpha values

par(linesj)
        lns <- slotmfcol=c(lspl2, "lines"2)
        polys <- sapply(lns, function(x) { 
          crds <-for slot(slot(x, "Lines")[[1]], "coords")
        a in identicalc(crds[1500, ]1500, crds[nrow(crds)5000, ])
        }100000) 
        polyssl <- lspl[polys]
        list_of_Lines <- slot(polyssl, "lines")
        sppolys <- SpatialPolygons(list(Polygons(lapply(list_of_Lines, function(x) {
    Polygon(slot(slot(x, "Lines")[[1]], "coords")) }), ID = "1")), proj4string=proj4string)
        hidch <- sapply(slotconvexHull(sppolys, "polygons")meuse, function(x)alpha slot(x,= "ID")a)
          areas <- sapply(slot(sppolys, "polygons"), function(x) slotplot(x, "area")ch)
          df <- data.framepoints(hidmeuse,areas)
            names(df) <- c("HID","Area"pch=19)
            rownamestitle(df) <- df$HID
        res <- SpatialPolygonsDataFramepaste0(sppolys"alpha=", data=df)
       res <- res[which(res@data$Area > 0a),]
      }  
      return(res)
   }
   a <- ahull(x.coords, alpha=alpha)
    return(ahull2sp(a, rnd=rnd)) 
}
######################################################################################
# PROGRAM: ConvexHull 
# USE: CREATE CONVEX HULL USING THE Pateiro-Lopez ALPHAHULL MODEL  
# REQUIRES: sp, alphahull, maptools 
#                                                                                                                                                                                                     
# ARGUMENTS:  
#       x          sp Points CLASS OBJECT                       
#       alpha      CONVEX HULL ALPHA VALUE (SEE ?alphahull)
#       increment  DEFAULT 360    
#       rnd        DEFAULT 2
# 
# VALUE:  
#      A sp SpatialPolygonsDataFrame OBJECT         
#
# NOTES:
#    THIS METHOD PROVIDES FLEXIBILITY OVER TRADITIONAL CONVEX FUNCTIONS. YOU CAN 
#      ADJUST THE ALPHA PARAMETER TO RELAX OR INCREASE TENSION BETWEEN EDGE-BOUNDARY
#      POINTS TO CREATE MORE OF AN EXACT FIT OF THE ENVELOPE (SEE EXAMPLE).
#
# REFERENCES:
#    Pateiro-López & Rodríguez-Casal (2009) Generalizing the Convex Hull of a Sample: 
#      The R Package alphahull. Journal of Statistical Software 34(5):1-28 
#      http://www.jstatsoft.org/v34/i05/paper
#                                                                       
# EXAMPLES: 
#    require(sp)
#    data(meuse)
#    coordinates(meuse) = ~x+y
#    a <- ConvexHull(meuse, alpha=100000)
#      plot(a)
#        points(meuse, pch=19)
#    # TEST MULTIPLE alpha VALUES
#    a=c(1000, 100000)
#     par(mfcol=c(1,2))
#       for (alpha in a) {
#       ch <- ConvexHull(meuse, alpha=alpha)
#         plot(ch)
#          points(meuse, pch=19) 
#       }
#                                                                                   
# CONTACT:
#     Jeffrey S. Evans
#     Senior Landscape Ecologist  
#     The Nature Conservancy
#     Central Science/DbyD
#     Affiliate Assistant Professor
#     Environment and Natural Resources
#     University of Wyoming
#     Laramie, WY 82070 
#     [email protected]
#     (970) 672-6766
######################################################################################  
ConvexHull <- function(x, alpha=250000, increment=360, rnd=2)   {
    if (!require (sp)) stop("sp PACKAGE MISSING")
      if (!require (alphahull)) stop("sp PACKAGE MISSING")
        if (!require(maptools)) stop("maptools PACKAGE MISSING")
    if (!inherits(x, "SpatialPointsDataFrame") |  !inherits(x, "SpatialPoints") ) 
      stop(deparse(substitute(x)), " MUST BE A sp Points OBJECT")
        x.coords <- coordinates(x)    
    ahull2sp <- function(x, increment=360, rnd=10, proj4string=CRS(as.character(NA))){
      if (class(x) != "ahull")
        stop("x needs to be an ahull class object")
      xdf <- as.data.frame(x$arcs)
      xdf <- subset(xdf,xdf$r > 0)
      res <- NULL
      if (nrow(xdf) > 0){
        linesj <- list()
        prevx<-NULL
        prevy<-NULL
        j<-1
        for(i in 1:nrow(xdf)){
          rowi <- xdf[i,]
          v <- c(rowi$v.x, rowi$v.y)
          theta <- rowi$theta
          r <- rowi$r
          cc <- c(rowi$c1, rowi$c2)
          ipoints <- 2 + round(increment * (rowi$theta / 2),0)
          angles <- anglesArc(v, theta)
          seqang <- seq(angles[1], angles[2], length = ipoints)
          x <- round(cc[1] + r * cos(seqang),rnd)
          y <- round(cc[2] + r * sin(seqang),rnd)
          if (is.null(prevx)){
            prevx<-x
            prevy<-y
          } else if (x[1] == round(prevx[length(prevx)],rnd) && y[1] == round(prevy[length(prevy)],rnd)){
              if (i == nrow(xdf)){
                prevx<-append(prevx,x[2:ipoints])
                prevy<-append(prevy,y[2:ipoints])
                prevx[length(prevx)]<-prevx[1]
                prevy[length(prevy)]<-prevy[1]
                coordsj<-cbind(prevx,prevy)
                colnames(coordsj)<-NULL
                linej <- Line(coordsj)
                linesj[[j]] <- Lines(linej, ID = as.character(j))
              } else {
                prevx<-append(prevx,x[2:ipoints])
                prevy<-append(prevy,y[2:ipoints])
              }
            } else {
              prevx[length(prevx)]<-prevx[1]
              prevy[length(prevy)]<-prevy[1]
              coordsj<-cbind(prevx,prevy)
              colnames(coordsj)<-NULL
              linej <- Line(coordsj)
              linesj[[j]] <- Lines(linej, ID = as.character(j))
              j<-j+1
              prevx<-NULL
              prevy<-NULL
            }
        }
        lspl <- SpatialLines(linesj)
        lns <- slot(lspl, "lines")
        polys <- sapply(lns, function(x) { 
          crds <- slot(slot(x, "Lines")[[1]], "coords")
          identical(crds[1, ], crds[nrow(crds), ])
        }) 
        polyssl <- lspl[polys]
        list_of_Lines <- slot(polyssl, "lines")
        sppolys <- SpatialPolygons(list(Polygons(lapply(list_of_Lines, function(x) {
    Polygon(slot(slot(x, "Lines")[[1]], "coords")) }), ID = "1")), proj4string=proj4string)
        hid <- sapply(slot(sppolys, "polygons"), function(x) slot(x, "ID"))
          areas <- sapply(slot(sppolys, "polygons"), function(x) slot(x, "area"))
          df <- data.frame(hid,areas)
            names(df) <- c("HID","Area")
            rownames(df) <- df$HID
        res <- SpatialPolygonsDataFrame(sppolys, data=df)
       res <- res[which(res@data$Area > 0),]
      }  
      return(res)
   }
   a <- ahull(x.coords, alpha=alpha)
    return(ahull2sp(a, rnd=rnd)) 
}

**Update (01-15-2018) There have been numerous changes to the resulting objects produced by the alphahull package. As such, I needed to rewrite the function. I added a convexHull function to the spatialEco package. However, due to licensing restrictions in the alphahull package this function is only available in the development version on GitHub. The development version can be installed using:

library(devtools)
install_github("jeffreyevans/spatialEco")

Here is an example of the functions usage

library(sp)
library(spatialEco)
data(meuse)
 coordinates(meuse) = ~x+y
a <- convexHull(meuse, alpha=100000)
  plot(a)
    points(meuse, pch=19)

Convert the resulting SpatialLinesDataFrame to SpatialPolygonsDataFrame

library(sf)
a <- sf::st_as_sf(a) 
a <- sf::st_polygonize(a)
class( a <- as(a, "Spatial") )
  plot(a)

Test multiple alpha values

par(mfcol=c(2,2))
   for (a in c(500, 1500, 5000, 100000)) {
   ch <- convexHull(meuse, alpha = a)
     plot(ch)
      points(meuse, pch=19)
        title( paste0("alpha=", a))      
   }
Source Link
Jeffrey Evans
  • 32k
  • 2
  • 48
  • 97

Here is an R function that implements the Alpha Hull model. The output is an sp polygon object. Please see the example in the header. It requires the sp, alphahull and maptools packages.

######################################################################################
# PROGRAM: ConvexHull 
# USE: CREATE CONVEX HULL USING THE Pateiro-Lopez ALPHAHULL MODEL  
# REQUIRES: sp, alphahull, maptools 
#                                                                                                                                                                                                     
# ARGUMENTS:  
#       x          sp Points CLASS OBJECT                       
#       alpha      CONVEX HULL ALPHA VALUE (SEE ?alphahull)
#       increment  DEFAULT 360    
#       rnd        DEFAULT 2
# 
# VALUE:  
#      A sp SpatialPolygonsDataFrame OBJECT         
#
# NOTES:
#    THIS METHOD PROVIDES FLEXIBILITY OVER TRADITIONAL CONVEX FUNCTIONS. YOU CAN 
#      ADJUST THE ALPHA PARAMETER TO RELAX OR INCREASE TENSION BETWEEN EDGE-BOUNDARY
#      POINTS TO CREATE MORE OF AN EXACT FIT OF THE ENVELOPE (SEE EXAMPLE).
#
# REFERENCES:
#    Pateiro-López & Rodríguez-Casal (2009) Generalizing the Convex Hull of a Sample: 
#      The R Package alphahull. Journal of Statistical Software 34(5):1-28 
#      http://www.jstatsoft.org/v34/i05/paper
#                                                                       
# EXAMPLES: 
#    require(sp)
#    data(meuse)
#    coordinates(meuse) = ~x+y
#    a <- ConvexHull(meuse, alpha=100000)
#      plot(a)
#        points(meuse, pch=19)
#    # TEST MULTIPLE alpha VALUES
#    a=c(1000, 100000)
#     par(mfcol=c(1,2))
#       for (alpha in a) {
#       ch <- ConvexHull(meuse, alpha=alpha)
#         plot(ch)
#          points(meuse, pch=19) 
#       }
#                                                                                   
# CONTACT:
#     Jeffrey S. Evans
#     Senior Landscape Ecologist  
#     The Nature Conservancy
#     Central Science/DbyD
#     Affiliate Assistant Professor
#     Environment and Natural Resources
#     University of Wyoming
#     Laramie, WY 82070 
#     [email protected]
#     (970) 672-6766
######################################################################################  
ConvexHull <- function(x, alpha=250000, increment=360, rnd=2)   {
    if (!require (sp)) stop("sp PACKAGE MISSING")
      if (!require (alphahull)) stop("sp PACKAGE MISSING")
        if (!require(maptools)) stop("maptools PACKAGE MISSING")
    if (!inherits(x, "SpatialPointsDataFrame") |  !inherits(x, "SpatialPoints") ) 
      stop(deparse(substitute(x)), " MUST BE A sp Points OBJECT")
        x.coords <- coordinates(x)    
    ahull2sp <- function(x, increment=360, rnd=10, proj4string=CRS(as.character(NA))){
      if (class(x) != "ahull")
        stop("x needs to be an ahull class object")
      xdf <- as.data.frame(x$arcs)
      xdf <- subset(xdf,xdf$r > 0)
      res <- NULL
      if (nrow(xdf) > 0){
        linesj <- list()
        prevx<-NULL
        prevy<-NULL
        j<-1
        for(i in 1:nrow(xdf)){
          rowi <- xdf[i,]
          v <- c(rowi$v.x, rowi$v.y)
          theta <- rowi$theta
          r <- rowi$r
          cc <- c(rowi$c1, rowi$c2)
          ipoints <- 2 + round(increment * (rowi$theta / 2),0)
          angles <- anglesArc(v, theta)
          seqang <- seq(angles[1], angles[2], length = ipoints)
          x <- round(cc[1] + r * cos(seqang),rnd)
          y <- round(cc[2] + r * sin(seqang),rnd)
          if (is.null(prevx)){
            prevx<-x
            prevy<-y
          } else if (x[1] == round(prevx[length(prevx)],rnd) && y[1] == round(prevy[length(prevy)],rnd)){
              if (i == nrow(xdf)){
                prevx<-append(prevx,x[2:ipoints])
                prevy<-append(prevy,y[2:ipoints])
                prevx[length(prevx)]<-prevx[1]
                prevy[length(prevy)]<-prevy[1]
                coordsj<-cbind(prevx,prevy)
                colnames(coordsj)<-NULL
                linej <- Line(coordsj)
                linesj[[j]] <- Lines(linej, ID = as.character(j))
              } else {
                prevx<-append(prevx,x[2:ipoints])
                prevy<-append(prevy,y[2:ipoints])
              }
            } else {
              prevx[length(prevx)]<-prevx[1]
              prevy[length(prevy)]<-prevy[1]
              coordsj<-cbind(prevx,prevy)
              colnames(coordsj)<-NULL
              linej <- Line(coordsj)
              linesj[[j]] <- Lines(linej, ID = as.character(j))
              j<-j+1
              prevx<-NULL
              prevy<-NULL
            }
        }
        lspl <- SpatialLines(linesj)
        lns <- slot(lspl, "lines")
        polys <- sapply(lns, function(x) { 
          crds <- slot(slot(x, "Lines")[[1]], "coords")
          identical(crds[1, ], crds[nrow(crds), ])
        }) 
        polyssl <- lspl[polys]
        list_of_Lines <- slot(polyssl, "lines")
        sppolys <- SpatialPolygons(list(Polygons(lapply(list_of_Lines, function(x) {
    Polygon(slot(slot(x, "Lines")[[1]], "coords")) }), ID = "1")), proj4string=proj4string)
        hid <- sapply(slot(sppolys, "polygons"), function(x) slot(x, "ID"))
          areas <- sapply(slot(sppolys, "polygons"), function(x) slot(x, "area"))
          df <- data.frame(hid,areas)
            names(df) <- c("HID","Area")
            rownames(df) <- df$HID
        res <- SpatialPolygonsDataFrame(sppolys, data=df)
       res <- res[which(res@data$Area > 0),]
      }  
      return(res)
  }
   a <- ahull(x.coords, alpha=alpha)
    return(ahull2sp(a, rnd=rnd)) 
}