Search code examples
rpolygonspatialanglecentroid

Create spatial line through point at a given angle


I have a spatial polygon, for example the shape of Greenland:

library("rnaturalearth")
Greenland <- ne_countries(scale = "medium", country="Greenland")
plot(Greenland)

and I know how to calculate its geometric center, i.e. centroid:

library("rgeos")
Greenland_cent <- gCentroid(Greenland)
plot(Greenland_cent,add=T,col="red")

Now I'd like to create lines at various angles that all pass through the centroid in order to cut Greenland into half (approximately, edit: As mentioned by @Henry this might not be exactly the half). However, I've not found any method yet that allows to create lines specified by an angle... ...any ideas?

Or are there any other methods to cut a polygon into two parts of approximately or even exactly the same size?


Solution

  • I implemented the line using trigonometry. I assumed you would always want to have the line start and end on or outside Greenland, so I find the smallest enclosing circle and make the lines start or end on this. Cutting a shape in two is more work but I suppose you could create two semi circles using the coordinates and use these to mask the original Greenland shape to make two new ones. From there the centroids and areas are easy.

    library(rnaturalearth)
    library(sp)
    library(rgeos)
    library(raster)
    projection <- '+proj=stere +lat_0=90 +lat_ts=90 +lon_0=-33 +k=0.994 +x_0=2000000 +y_0=2000000 +datum=WGS84 +units=m +no_defs '
    Greenland.raw <- ne_countries(scale = "medium", country="Greenland")
    # use a different projection to avoid some warnings
    Greenland = spTransform(Greenland.raw, CRSobj = projection)
    Greenland_cent <- gCentroid(Greenland)
    # Make a simpler Greenland shape - expand and contract to smooth out the crinkly edges 
    SimplerGreenland <- gBuffer(gBuffer(Greenland, width = 1), width=-1)
    # Make a line from the shape
    SimplerGreenlandLine <- as(SimplerGreenland, 'SpatialLines')
    # sample all around the simpler line
    PointsAroundGreenland <- spsample(x = SimplerGreenlandLine, n = 1000, type = 'regular')
    # find the furthest point from the centroid
    distances <- gDistance(PointsAroundGreenland, Greenland_cent, byid = T)
    furthestpointfromcentroid <- distances[which.max(distances)]
    # make the smallest circle that encloses Greenland to ensure that any line we draw will be in Greenland
    enclosingcircle <- gBuffer(spgeom = Greenland_cent, width = furthestpointfromcentroid, quadsegs = 100)
    # choose an angle and make a line that goes through the centroid and starts and ends on the enclosing circle
    angleindegrees <- 5
    angle <- angleindegrees * pi / 180
    dx <- furthestpointfromcentroid * cos(angle)
    dy <- furthestpointfromcentroid * sin(angle)
    centroid <- as.numeric(coordinates(Greenland_cent))
    x1 <- centroid[1] + dx
    y1 <- centroid[2] + dy
    x2 <- centroid[1] - dx
    y2 <- centroid[2] - dy
    l1 <- Line(cbind(c(x1,x2), c(y1,y2)))
    l2 <- Lines(list(l1), ID = 'line')
    lineatangle <- SpatialLines(list(l2))
    crs(lineatangle) <- crs(Greenland)
    
    # plot everything
    plot(Greenland)
    plot(Greenland_cent, add = T, col = 'red')
    plot(lineatangle, add = T, col = 'green')
    

    enter image description here