[R-sig-Geo] alpha hull (ahull) to polygon shapefile
Andrew Bevan
a.bevan at ucl.ac.uk
Sun Mar 4 20:03:20 CET 2012
Dear Kevin
As far as I remember, the ahull class object stores its information in arcs that are not a straight conversion to standard GIS-style lines or polygons. I played with the following function some time ago and it is very rough (apologies in advance), but it works for my purposes. Its starting point was a script for conversion to lines only by Dylan Beaudette that the latter may be sufficient for you (http://casoilresource.lawr.ucdavis.edu/drupal/node/919). In contrast, the version below models the alphahull arcs with a user-defined line segment increment and tries to borrow a polygon-building method from the ASDAR book to create a SpatialPolygonsDataFrame object. Both the function and a toy example below.
Andy
########################
ah2sp <- function(x, increment=360, rnd=10, proj4string=CRS(as.character(NA))){
require(alphahull)
require(maptools)
if (class(x) != "ahull"){
stop("x needs to be an ahull class object")
}
# Extract the edges from the ahull object as a dataframe
xdf <- as.data.frame(x$arcs)
# Remove all cases where the coordinates are all the same
xdf <- subset(xdf,xdf$r > 0)
res <- NULL
if (nrow(xdf) > 0){
# Convert each arc to a line segment
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)
# Arcs need to be redefined as strings of points. Work out the number of points to allocate in this arc segment.
ipoints <- 2 + round(increment * (rowi$theta / 2),0)
# Calculate coordinates from arc() description for ipoints along the arc.
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)
# Check for line segments that should be joined up and combine their coordinates
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)){
#We have got to the end of the dataset
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
# Build as Line and then Lines class
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 {
# We have got to the end of a set of lines, and there are several such sets, so convert the whole of this one to a line segment and reset.
prevx[length(prevx)]<-prevx[1]
prevy[length(prevy)]<-prevy[1]
coordsj<-cbind(prevx,prevy)
colnames(coordsj)<-NULL
# Build as Line and then Lines class
linej <- Line(coordsj)
linesj[[j]] <- Lines(linej, ID = as.character(j))
j<-j+1
prevx<-NULL
prevy<-NULL
}
}
# Promote to SpatialLines
lspl <- SpatialLines(linesj)
# Convert lines to polygons
# Pull out Lines slot and check which lines have start and end points that are the same
lns <- slot(lspl, "lines")
polys <- sapply(lns, function(x) {
crds <- slot(slot(x, "Lines")[[1]], "coords")
identical(crds[1, ], crds[nrow(crds), ])
})
# Select those that do and convert to SpatialPolygons
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)
# Create a set of ids in a dataframe, then promote to SpatialPolygonsDataFrame
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 at data$Area > 0),]
}
return(res)
}
########################
#So for example:
library(alphahull)
library(maptools)
n <- 300
theta <- runif(n,0,2*pi)
r <- sqrt(runif(n,0.25^2,0.5^2))
x <- cbind(0.5+r*cos(theta),0.5+r*sin(theta))
a <- ahull(x, alpha = 0.1)
plot(a)
#Convert
b <- ah2sp(a)
plot(b, col="lightgrey", pbg="white")
#Write to shapefile
writeSpatialShape(b, "b")
On 4 Mar 2012, at 18:52, Kevin Goulding wrote:
> I would like to convert a point shapefile into a polygon shapefile
> containing an alpha hull of the points. I've imported the point shapefile
> and calculated the desired alpha hull:
>
> #######################################
> require(spdep)
> require(alphahull)
>
> ccPoints=readShapeSpatial('myshapefile')
> a=5000
>
> x.coords <- coordinates(ccPoints)
> x.ah <- ahull(x.coords[,1], x.coords[,2], alpha=a)
>
> # plot the concave alpha hull:
> # plot(x.ah,col='purple',add=T,asp=1,cex=0, pch=4)
> # looks good...
>
> # now, would like to export alpha hull as a shapefile with a single polygon
> # something like this:
> # write.shp(x.ah, file = 'ahull-shapefile.shp')
> #######################################
>
> How do I output a polygon shapefile containing the alpha hull?
>
> Many thanks, Kevin
>
> [[alternative HTML version deleted]]
>
> _______________________________________________
> R-sig-Geo mailing list
> R-sig-Geo at r-project.org
> https://stat.ethz.ch/mailman/listinfo/r-sig-geo
>
More information about the R-sig-Geo
mailing list