Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Filling polygon holes based on area #609

Closed
lbusett opened this issue Jan 8, 2018 · 15 comments
Closed

Filling polygon holes based on area #609

lbusett opened this issue Jan 8, 2018 · 15 comments

Comments

@lbusett
Copy link
Contributor

lbusett commented Jan 8, 2018

Hi all,

just a quick check before starting reinventing the weel.
Is there a function / quick solution for removing ("filling") the holes of a polygon based on their area?

In practice, the functionality would allow to go from this:

suppressPackageStartupMessages(library(sf))
p1 <- rbind(c(0,0), c(1,0), c(3,2), c(2,4), c(1,4), c(0,0))
p2 <- rbind(c(1,1), c(1,2), c(2,2), c(1,1))
p3 <- rbind(c(1,2.2), c(1,2.4), c(1.2,2.4), c(1,2.2))
pol <-st_polygon(list(p1,p2,p3))
plot(pol)

to this:

pol_filled <- fill_holes(pol, min_area = 0.4)
plot(pol_filled)

, with min_area correponding to the minimum area of "retained" holes.

I know I could work my way out by looping over the inner rings of the polygons and checking their area more or less like this:

min_area <- 0.4
# Get the outer ring
pol_filled <- st_polygon(pol[1])
if (length(pol) > 1) {
  h_ind <- 2
  for (hole in 2:length(pol)) {
    # Check area of inner ring - preserve hole if area > thresh
    if ((st_polygon(pol[hole]) %>% sf::st_area()) >= min_area) {
      pol_filled[h_ind] <- st_polygon(pol[hole])
      h_ind <- h_ind + 1
    }
  }
}

, but I was wondering if there was already a "cleaner" solution for this.

Also, I'd wonder if it would make sense to include this kind of functionality within sf, as a way (for example) to "clean" geometries, since it would allow to easily remove small polygon slivers.

Thanks in advance !

@tim-salabim
Copy link
Member

Just as a general comment, slivers are not necessarily best described by their "small" area. There's a nice powerpoint presentation at this page that highlights a few standard shape metrics. I think a smart combination of these could produce a powerful sliver detection/removal tool.

@lbusett
Copy link
Contributor Author

lbusett commented Jan 8, 2018

@tim-salabim : You're obviously right. I was in fact starting to think on how to possibly remove "long and narrow" polygons, for which the area criterion could not suffice. The presentation you shared is very promising on that respect. Thanks for sharing.

@jsta
Copy link
Contributor

jsta commented Jan 8, 2018

I have been planning on writing an sf add-on package to quantify various aspects of polygon shape building off the work done by myself and @jhollist in the lakemorpho package. Happy for comments, collaborations, or pointers to existing work in this space!

@edzer
Copy link
Member

edzer commented Jan 12, 2018

OK thanks; closing here, please reopen if needed.

@edzer edzer closed this as completed Jan 12, 2018
@adrfantini
Copy link

Sorry for hijacking this, but is there any way, other than the loop provided above, to fill holes in a multipolygon (without a minimum area requirement)? I feel like this should be provided by base sf functions, but I can't find it.

@edzer
Copy link
Member

edzer commented Jan 13, 2018

Building on the example above, from

mp = st_multipolygon(list(pol, pol + 3, pol + c(-3,3)))

you can remove all holes by

st_multipolygon(lapply(mp, function(x) x[1]))

We could make this a function and think of a name, but then we would risk ending up with a GIS.

@adrfantini
Copy link

Maybe it's not the right place to discuss this, but what do you mean by:

we would risk ending up with a GIS

? Maybe I am missing something you have written in the past about the scope of the project.

The function provided seems quite specific to me: does not work with multipolygons and with generic sf objects: you would in theory want a function that can take as input any of that. See poly.zip, an example of a small subset of an sf object which I'd like to fill (to be loaded with load(poly.zip)).

@edzer
Copy link
Member

edzer commented Jan 13, 2018

No you didn't miss anything, and it was tongue in cheek. I associate most GIS software with Christmas tree GUIs having an infinite number of bells and whistles, but have to admit not being a frequent user.

The zip file you point to looks broken, on my end.

@adrfantini
Copy link

adrfantini commented Jan 14, 2018

I see your point, but doesn't sf want to enable R users to keep their entire workflow in R, without having to resort to admittedly sometimes awkward GIS programs? If that's the case, and it's up to you, you'll want to reach if not feature parity, at least provide the main features, right? Just asking, sf is awesome and I'm just curious as to the direction of the project.

EDIT: (I'm also definitely not a huge fan of GIS programs, and I cringe every time I have to resort to QGIS to do something, so I definitely see what you mean.)

As for the zip file, works file for me (redownloaded): did you try loading it directly, without unzipping? I produced it with save(), but set a .zip extension instead of a more usual .Rdata so that github would allow uploading.

@lbusett
Copy link
Contributor Author

lbusett commented Jan 14, 2018

I think (correct me if I am wrong) that @edzer would like to keep the number of sf functions as tight as possible. I see his point, since implementing any possible "GIS-like" functionality could rapidly escalate things, making the package difficult to maintain. In this context, I think @jsta idea of "add-on" packages that build on sf bricks to provide "higher level" GIS-like functionality could be a good one, and could also benefit other packages (e.g., mapedit). @jsta: I'm interested in your idea. Will contact you in the issue page of your package.

@edzer
Copy link
Member

edzer commented Jan 14, 2018

@adrfantini sorry I hadn't tried the load(poly.zip); see it now. It also illustrates the regression of print(poly) now taking several seconds; introduced while fixing #577.

As of the scope of R and sf: I think that we would like to be able to do entire workflows with R, but not entirely using exclusively sf. Look how things developed around package sp since it appeared 13 years ago on CRAN: lots of other packages were developed to solve much more specific problems than sp does. Maintenance is not the largest problem: understanding what sf is for once it contains more than 200 functions is. Your function for removing holes is only the start of a much larger and harder problem of cleaning up complex, possibly non-simple or non-valid polygon data.

@edzer
Copy link
Member

edzer commented Jan 14, 2018

See also this thread

@adrfantini
Copy link

So basically you are telling me I shouldn't file a feature request for a "st_fill_holes" function, since you are expecting this kind of expansion to take place in add-on packages, right? I personally feel like this feature in particular is pretty basic and would not look misplaced in sf.

@edzer
Copy link
Member

edzer commented Jan 15, 2018

I can only decide on a PR after I see one; you can look at the trace of PRs that got accepted and others that were not merged, along with discussions. You can see some recent ones that came with very extensive and good arguments.

@jsta
Copy link
Contributor

jsta commented Feb 7, 2019

A function for filling polygon holes based on area can be found in the smoothr package smoothr::fill_holes - http://strimas.com/smoothr/reference/fill_holes.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants