eblondel / cleangeo

Cleaning geometries from spatial objects in R
https://github.com/eblondel/cleangeo/wiki
45 stars 2 forks source link

Error with NULL polygons during cleaning #22

Closed ghost closed 7 years ago

ghost commented 7 years ago

I used R to convert a publicly-available .kml file to .shp. Then I imported it into R with readOGR(). I ran clgeo_Clean() with verbose = TRUE and after a time it threw:

Error in slot(x, "coords") : 
  cannot get a slot ("coords") from an object of type "NULL"

with traceback() output:

12: slot(x, "coords")
11: FUN(X[[i]], ...)
10: lapply(po, function(x) {
        outpo <- x
        coords <- slot(x, "coords")
        coords[, 1] <- as.character(coords[, 1])
        coords[, 2] <- as.character(coords[, 2])
        if (nrow(unique(slot(x, "coords"))) < 3) 
            outpo <- NULL
        return(outpo)
    })
9: FUN(X[[i]], ...)
8: lapply(1:length(holes), function(i) {
       hole <- holes[[i]]
       temphole <- SpatialPolygons(Srl = list(Polygons(srl = list(hole), 
           ID = "1")))
       po <- hole
       isValid <- clgeo_IsValid(temphole, verbose)
       if (!isValid) {
           po <- clgeo_CleanByPolygonation.Polygon(hole, verbose)
       }
       if (!is.list(po)) 
           po <- list(po)
       po <- lapply(po, function(x) {
           outpo <- x
           coords <- slot(x, "coords")
           coords[, 1] <- as.character(coords[, 1])
           coords[, 2] <- as.character(coords[, 2])
           if (nrow(unique(slot(x, "coords"))) < 3) 
               outpo <- NULL
           return(outpo)
       })
       po <- po[!sapply(po, is.null)]
       out <- NULL
       if (!is.null(po) && length(po) > 0) {
           if (!is.list(po)) 
               po <- list(po)
           polyholes <- Polygons(srl = po, ID = as.character(ID))
           if (slot(polyholes, "area") > 0) 
               out <- polyholes
           if (!is.null(out)) {
               if (slot(polyholes, "area") >= (1/rgeos::getScale())) {
                   ID <<- ID + 1
               }
               else {
                   out <- NULL
               }
           }
       }
       return(out)
   })
7: FUN(X[[i]], ...)
6: lapply(sp@polygons, clgeo_CleanByPolygonation.Polygons, verbose)
5: unlist(lapply(sp@polygons, clgeo_CleanByPolygonation.Polygons, 
       verbose))
4: clgeo_CleanByPolygonation.SpatialPolygons(polygon, verbose)
3: FUN(X[[i]], ...)
2: lapply(1:length(sp), function(x) {
       polygon <- slot(sp, "polygons")[[x]]
       ID <- slot(polygon, "ID")
       if (!all(is.na(nv))) {
           if (x %in% nv) {
               polygons <- slot(polygon, "Polygons")
               poly.nb <- length(polygons)
               removedHoles <- vector()
               if (poly.nb > 0) {
                   newpolygons <- list()
                   for (i in 1:poly.nb) {
                     if (slot(polygons[[i]], "hole")) {
                       if (dim(unique(slot(polygons[[i]], "coords")))[1] < 
                         3) {
                         if (length(removedHoles) == 0 & verbose) {
                           logger.info(sprintf("Cleaning orphaned holes at index %s", 
                             x))
                         }
                         removedHoles <- c(removedHoles, i)
                       }
                       else {
                         newpolygon <- polygons[[i]]
                         slot(newpolygon, "hole") <- TRUE
                         newpolygons <- c(newpolygons, newpolygon)
                       }
                     }
                     else {
                       newpolygon <- polygons[[i]]
                       slot(newpolygon, "hole") <- FALSE
                       newpolygons <- c(newpolygons, newpolygon)
                     }
                   }
                   slot(polygon, "Polygons") <- newpolygons
               }
               polygon <- SpatialPolygons(Srl = list(polygon))
               isValid <- report[x, ]$valid
               if (length(removedHoles) > 0) {
                   if (verbose) {
                     logger.info(sprintf("Checking geometry validity at index %s", 
                       x))
                   }
                   tryCatch({
                     slot(polygon, "polygons") <<- lapply(slot(polygon, 
                       "polygons"), checkPolygonsHoles)
                   }, warning = function(msg) {
                     if (verbose) 
                       logger.info(sprintf("Catched MAPTOOLS warning '%s'", 
                         msg))
                   }, error = function(err) {
                     if (verbose) 
                       logger.info(sprintf("Catched MAPTOOLS error '%s'", 
                         err))
                   })
                   isValid <<- clgeo_IsValid(polygon, verbose)
               }
               if (is.null(errors.only) & !isValid) {
                   if (verbose) {
                     report.msg <- NULL
                     if (!is.na(report[x, "error_msg"])) {
                       report.msg <- report[x, "error_msg"]
                     }
                     else if (!is.na(report[x, "warning_msg"])) {
                       report.msg <- report[x, "warning_msg"]
                     }
                     logger.info(sprintf("Cleaning geometry at index %s (%s)", 
                       x, report.msg))
                   }
                   if (strategy == "POLYGONATION") {
                     polygon <- clgeo_CleanByPolygonation.SpatialPolygons(polygon, 
                       verbose)
                   }
                   else if (strategy == "BUFFER") {
                     attempt <- 1
                     polygon <- gBuffer(polygon, id = ID, width = 0)
                     while (attempt < 3) {
                       if (!clgeo_IsValid(polygon, verbose)) {
                         attempt <- attempt + 1
                         polygon <- gBuffer(polygon, id = ID, width = 0)
                       }
                       else {
                         break
                       }
                     }
                   }
               }
               if (!is.null(polygon)) {
                   polygon <- polygon@polygons[[1]]
                   slot(polygon, "ID") <- ID
               }
               else {
                   if (verbose) {
                     logger.info(sprintf("Removing false polygon at index %s", 
                       x))
                   }
               }
           }
       }
       return(polygon)
   })
1: clgeo_Clean(asentamiento.shp.orig, verbose = TRUE)

I will email @eblondel the file.

eblondel commented 7 years ago

@tdmcarthur I've made a minor fix in the code. I've tried to run it on the complete shapefile without exception raised. Let me know if it works for you

sp.clean <- clgeo_Clean(sp, verbose = TRUE)
ok <- all(sapply(1:nrow(sp.clean),function(x){return(gIsValid(sp.clean[x,]))}))
ghost commented 7 years ago

Thanks for making the fix so quickly! I tried it again with the new build of the package and I had no problems.