-
Notifications
You must be signed in to change notification settings - Fork 33
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
deleting holes with editor leafpm returns invalid sf #88
Comments
@tim-salabim great idea. Please let me know if I got close to your expectation. Thanks! |
I noticed that this only appears to happen on multipolygons. Casting to POLYGON beforehand and then removing a hole returns valid geometries:
Looking at the WKTs returned after removing the hole on the multipolygon:
it seems that (if I understand WKT properly), we are missing a couple of parenthesis (After "...1, 1 1)" and before "(11 0, 11..", so that the second polygon "appears" to be a hole of the first one. Could this be a bug in the leafpm plugin? PS: Id'also be careful if possible with HTH |
Thanks @lbusett! I think you are right that the polygon structure gets mangled up. Indeed seems like an issue in leaflet.pm. Can you please elaborate on what you mean by
Any examples where it does something unexpected? I have never experienced any problems other than that some geometries cannot be repaired iirc... |
Hi @tim-salabim. I agree that the "main" problem is in failing to repair geometries. That can be easily "intercepted" (I think @timelyportfolio implemented that, but I wonder if it wouldn't be better to issue an Error, in that case, instead of returning an invalid geometry). I however think that even in case of success, there are cases where results of library(lwgeom)
#> Linking to liblwgeom 2.5.0dev r16016, GEOS 3.6.1, PROJ 4.9.3
library(sf)
#> Linking to GEOS 3.6.1, GDAL 2.2.3, PROJ 4.9.3
outer = matrix(c(0,0,10,0,10,10,11,10, 10,10, 0,10,0,0),ncol=2, byrow=TRUE)
pts = list(outer)
pl = st_sf(a = 100, geom = st_sfc(st_polygon(pts)))
plot(pl) st_is_valid(pl)
#> [1] FALSE
pl2 <- st_make_valid(pl)
st_is_valid(pl2)
#> [1] TRUE
st_astext(pl2)
#> [1] "GEOMETRYCOLLECTION(POLYGON((10 10,10 0,0 0,0 10,10 10)),LINESTRING(10 10,11 10))" here, in order to repair the geometry we go from a POLYGON to a GEOMETRYCOLLECTION, and a LINESTRING is introduced to maintain the number of vertexes. library(lwgeom)
#> Linking to liblwgeom 2.5.0dev r16016, GEOS 3.6.1, PROJ 4.9.3
library(sf)
#> Linking to GEOS 3.6.1, GDAL 2.2.3, PROJ 4.9.3
outer = matrix(c(0,0,10,0,10,10,0,10,10.1,5, 0,0),ncol=2, byrow=TRUE)
pts = list(outer)
pl = st_sf(a = 100, geom = st_sfc(st_polygon(pts)))
plot(pl) pl2 <- st_make_valid(pl)
st_is_valid(pl2)
#> [1] TRUE
st_astext(pl2)
#> [1] "MULTIPOLYGON(((10 5.049505,0 10,10 10,10 5.049505)),((10 4.950495,10 0,0 0,10 4.950495)),((10 4.950495,10 5.049505,10.1 5,10 4.950495)))" here we go from POLYGON to MULTIPOLYGON, introducing a small "triangle" on the right. Similar to this second example, but more related to outer = matrix(c(0,0,10,0,10,10,0,10,0,0),ncol=2, byrow=TRUE)
pts = list(outer)
pl = st_sf(a = 100, geom = st_sfc(st_polygon(pts)))
tst = editFeatures(mpl, editor = "leafpm") Clicking "Done" after editing like this currently returns an invalid geometry, and this can be checked afterwards. However, if plot(st_make_valid(tst)) Hope this is more or less clear and it makes sense. Apologies if I'm missing anything obvious (or you think these are just "made up" problems unlikely to occur ;-) ). |
@lbusett @tim-salabim thanks so much for the discussion and feedback. Let me see what I can do on the JavaScript side to handle these cases. I don't think there is a perfect solution, but it seems we can do better. |
@timelyportfolio Looking at the demo of leaf.pm (https://geoman.io/studio) it seems that it is possible to set the editor so to prevent self-intersection when creating/editing layers (by setting the allowSelfIntersection "argument" to FALSE) . I think that would be useful (Do not know what would happen however if "loading" a polygon with self-intersected features). |
Thanks @lbusett ! Those are great examples that highlight why we should indeed be careful with @timelyportfolio in light of these examples, I think we should not force valid geometries, but rather issue a warning if I think it is acceptable to burden the user with how to deal with invalid geometries. It is a pitty that we don't have a way of getting more information about what it is that makes a geometry invalid. |
Something along these lines? > ring = rbind(c(0,0), c(1,1), c(0,1), c(0,0))
> library(sf)
Linking to GEOS 3.7.0, GDAL 2.3.2, PROJ 5.2.0
> st_is_valid(st_polygon(list(ring, ring)))
[1] FALSE
> st_is_valid(st_polygon(list(ring, ring)), reason = TRUE)
[1] "Self-intersection[0 0]" |
@edzer perfect! Thanks! I did not know about So, it seems to me that it would be better to check whether edited/drawn features are valid and if not, raise a warning with the reason. Thoughts? |
@tim-salabim Makes sense to me. On a sidenote, I was thinking that it could maybe make sense to have a "repair_geoms" function in repair_geoms <- function(sf_object) {
invalid <- sf_object[!sf::st_is_valid(sf_object), ]
valid <- sf_object[sf::st_is_valid(sf_object), ]
out = editFeatures(invalid, editor = "leafpm")
if (all(st_is_valid(out))) {
rbind(valid, invalid)
} else {
message("still invalid")
}
} what do you think? |
Great idea! Fits well into the scope of mapedit. @timelyportfolio what do you think? |
@timelyportfolio along the lines of creating valid geometries, can we set style options so that when e.g. a self-intersection occurs the color of the drawn/edited geometry it changes color as in the examples shown here? |
@lbusett @tim-salabim I reverted the commits to check and try to repair validity. Should we save this for the next release? I definitely want to get this solved but worried that it might take some time to get it right. Will wait to hear. |
@timelyportfolio i agree that this may be too involved for the next release, especially given the deadline end of Jan. A test whether what has been done produced a valid geometry (together with a warning if it didn't) and having allowSelfIntersection set to false for polygons (if incoming feature is (multi)polygon) should suffice for now. |
@tim-salabim ok will test for valid and warn. I don't see where we can limit |
@tim-salabim @lbusett I upgraded to |
Can't we set the options of leafpm differently depending on what is coming in? |
Yes, but in the case of mixed feature types, we will have to choose one or the other. In the case of mixed, do you prefer |
In case of mixed features, there is one other layer of tests that we could add. If |
@tim-salabim I tried to add in 8521dd1 but it appears the |
If I do |
Looking good to me! Also the other additions ("moving " button and icons improvements) are quite nice. Small caveat: on the usual "test polygons with holes" used above, the user can still "eat a hole" doing this: The resulting geometry is invalid, with the "eaten hole" transformed in a new poly: I think however that the warning about invalid geoms is sufficient to deal with a case like this: if the user wants to make such a mess, it's his fault ;-) |
Took me a while to figure out what you were do there, but that just goes to show that we cannot cover all grounds and need users to behave sensibly. So warnings and errors in the correct places are more important than ever |
Coming back to the original issue, here you can find a tentative workaround for the "deleting holes" issue, at least for MULTIPOLYGON inputs. It is based on "splitting" the MULTIPOLYGON to polygon editing the multipolygon and then putting it back together exploiting the fact that when "casting" from MULTI to POLY the information about the "origins" of the different single polys is stored in the row.names of the casted object. It's a bit of a ugly workaround, so I did not do a PR yet, but maybe it could be a starting point (tested on a couple of datasets and seems to work). |
If we use the new
leafpm
editor to delete holes in polygons, the returned feature is invalid:I think we could simply wrap whatever comes back from the editing session in a
lwgeom::st_make_valid
inside atry(Catch)
call as it is not possible to know what users will draw/delete/edit anyway... Thoughts?The text was updated successfully, but these errors were encountered: