2

I have sfc LINESTRING and I would like to remove overlapping lines. Object data was created from an algorithm that joins lines with minimum distance. Using unique will not remove the initial lines.

In the example you can see that line 2 and 3 + other lines were the initial lines, then they were used to produce line 1, other lines were removed but 2 and 3 remained. and length of lines proves that!. Extracting the line with the maximum length will not work in my case because in some cases I have a non-overlaping line which I would like to keep!

> class(data)
[1] "sfc_LINESTRING" "sfc"           
> length(data)
[1] 3
> data
Geometry set for 3 features 
geometry type:  LINESTRING
dimension:      XY
bbox:           xmin: 181.4494 ymin: 4.441853 xmax: 278.9707 ymax: 14.72429
CRS:            +proj=longlat +datum=WGS84 +no_defs
LINESTRING (181.4494 4.462799, 181.4722 4.45583...
LINESTRING (181.4494 4.462799, 181.4722 4.45583...
LINESTRING (181.4494 4.462799, 181.4722 4.45583...

> st_overlaps(data,data)
although coordinates are longitude/latitude, st_overlaps assumes that they are planar
Sparse geometry binary predicate list of length 3, where the predicate was `overlaps'
 1: 2, 3
 2: 1, 3
 3: 1, 2

> st_length(data)
Units: [m]
[1] 11628206  7143693  9899478

Criteria to remove:

  • The line should be overlapping with other lines
  • The line is not the longest line.
3

Here's an approach using st_covered_by, which will return TRUE if a same sized or longer LINESTRING covers the geometry, the longest line here is the second feature, so the order does not matter, because it filters out the first line. The filtering part is hacky, but as you are comparing to the same sfobject you get a wide matrix object you'll have to fiddle around with

library(sf)
library(dplyr)
library(stringr)    
df = data.frame(key = c(1,2,3), wkt = c("LINESTRING (1 6, 2 7)","LINESTRING (1 6, 2 7, 3 8, 4 9, 5 10)", "LINESTRING (4 9, 5 10)" )) %>% 
  st_as_sf( wkt = "wkt")

df$covered = df %>% st_covered_by(.) %>% lengths > 1
df %>% filter(!covered)

EDIT

As @see24 pointed out, since January 2020 there's the function st_filter, which filters geometries with predicates such as st_covered_by, st_intersects, etc; however, as st_covered_by also returns TRUE if the lines are equal (this is why we filtered with > 1 and not > 0) . Instead, we may use a pattern from the DE-91M model in st_relate, in this case:

st_filter(df, df, .predicate =  st_relate, pattern = "1FFF0FFF2" )

You may check the pattern you want beforehand with:

 st_relate(df, df)
     [,1]        [,2]        [,3]       
[1,] "1FFF0FFF2" "1FF00F102" "FF1FF0102"
[2,] "101F00FF2" "1FFF0FFF2" "101F00FF2"
[3,] "FF1FF0102" "1FF00F102" "1FFF0FFF2"
2
  • 2
    It would be simpler if you used st_filter(df, df, .predicate = st_covered_by) – see24 Oct 30 '20 at 15:55
  • awesome, I didn't know about that function, I'm seeing it's from jan 2020; i'm this old: stackoverflow.com/questions/57014381/… – Elio Diaz Oct 30 '20 at 16:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.