[GIS] How to overcome invalid input geom and self-intersection when intersecting shapefiles in R

arcmaprrgeosself-intersection

I downloaded two shapefiles from IUCN (available here and here) to determine the range overlap between two species. When I bring the shapefiles into R, I am able to plot them on a map together, however, when I try to calculate percent overlap, I get this error:

 p <- readOGR(getwd(), layer="species_7928")
 w <- readOGR(getwd(), layer="species_21314")
 EPFU<- gArea(SpatialPolygons(p@polygons))
 intersected.area.tabr <- gArea(gIntersection(SpatialPolygons(w@polygons), 
 SpatialPolygons(p@polygons)))
 (intersected.area.tabr/EPFU)*100

  Error in RGEOSBinTopoFunc(spgeom1, spgeom2, byid, id,drop_lower_td,
  unaryUnion_if_byid_false,  : TopologyException: Input geom 0 is
  invalid: Ring Self-intersection at or near point -82.517899999999997 
  8.2930355900000006 at -82.517899999999997 8.2930355900000006

I've tried the suggested workarounds with gBuffer (width=0) and gUnaryUnion, but these also return errors.
I was also able to take a separate map provided by a friend from a different project and each of these files individually worked when I tried to calculate the intersection.
I can open these files together in ArcMap. I've run the check geometry tool there and the output table was empty. Is this occurring because there are multiple elements (discontinuous portions of the map)? I do not necessarily have to do this in R, if there is a straightforward way to do the same in ArcMap, but this is my first experience with any sort of GIS data.

Best Answer

Try the new simple features package (sf):

library("sf")
library("magrittr")

p <- st_read("species_7928.shp") %>%
     st_transform("+init=epsg:2163")  # project geometry
                                      # e.g. US National Atlas Equal Area
w <- st_read("species_21314.shp") %>%
     st_transform("+init=epsg:2163")
res <- st_intersection(st_geometry(p),
                       st_geometry(w))

plot(st_geometry(p), axes=TRUE)
plot(st_geometry(w), col="lightblue", add=TRUE)
plot(res, col="#FF000055", add=TRUE)

plot

sum(st_area(p))
# 1.279e+13 m^2
sum(st_area(w))
# 1.386e+13 m^2
sum(st_area(res))
# 6.108e+12 m^2