luukvdmeer / sfnetworks

Tidy Geospatial Networks in R
https://luukvdmeer.github.io/sfnetworks/
Other
347 stars 20 forks source link

to_spatial_subdivision merges nodes with equal coordinates #118

Open luukvdmeer opened 3 years ago

luukvdmeer commented 3 years ago

Describe the bug The goal of the to_spatial_subdivision morpher is to subdivide edges at locations where an interior point of that edges matches either an interior point or endpoint of another edge. Internally, it recreates a network. Unintentionally that means now that in networks that has different nodes with equal coordinates, these nodes ar merged into a single node. That is not the goal of the morpher and should therefore not happen. Or is this actually convenient? I am not sure.

Reproducible example The original network has two nodes (node 2 and node 3) with equal coordinates. Also it has an interior point in edge 1 that is shared with an interior point in edge 2. The subdivision morpher correctly subdivides edge 1 and edge 2 and adds a new node at their intersection. However, it also merged node 2 and node 3 into a single node.

library(sfnetworks)
library(sf)
#> Linking to GEOS 3.9.0, GDAL 3.2.0, PROJ 7.2.0
library(tidygraph)
#> 
#> Attaching package: 'tidygraph'
#> The following object is masked from 'package:stats':
#> 
#>     filter

p1 = st_point(c(0, 1))
p2 = st_point(c(3, 1))
p3 = st_point(c(4, 1))
p4 = st_point(c(3, 2))
p5 = st_point(c(3, 0))
p6 = st_point(c(4, 2))

pts = st_cast(st_sfc(c(p1, p3, p3, p4, p5, p6)), "POINT") 

l1 = st_sfc(st_linestring(c(p1, p2, p3)))
l2 = st_sfc(st_linestring(c(p4, p2, p5)))
l3 = st_sfc(st_linestring(c(p3, p6)))

lns = c(l1, l2, l3)

nodes = st_sf(geom = pts)
edges = st_sf(from = c(1, 4, 3), to = c(2, 5, 6), geom = lns)

net = sfnetwork(nodes, edges)
#> Checking if spatial network structure is valid...
#> Spatial network structure is valid
net
#> # A sfnetwork with 6 nodes and 3 edges
#> #
#> # CRS:  NA 
#> #
#> # A rooted forest with 3 trees with spatially explicit edges
#> #
#> # Node Data:     6 x 1 (active)
#> # Geometry type: POINT
#> # Dimension:     XY
#> # Bounding box:  xmin: 0 ymin: 0 xmax: 4 ymax: 2
#>      geom
#>   <POINT>
#> 1   (0 1)
#> 2   (4 1)
#> 3   (4 1)
#> 4   (3 2)
#> 5   (3 0)
#> 6   (4 2)
#> #
#> # Edge Data:     3 x 3
#> # Geometry type: LINESTRING
#> # Dimension:     XY
#> # Bounding box:  xmin: 0 ymin: 0 xmax: 4 ymax: 2
#>    from    to            geom
#>   <int> <int>    <LINESTRING>
#> 1     1     2 (0 1, 3 1, 4 1)
#> 2     4     5 (3 2, 3 1, 3 0)
#> 3     3     6      (4 1, 4 2)
plot(net)

new_net = convert(net, to_spatial_subdivision)
#> Warning: to_spatial_subdivision assumes attributes are constant over geometries
new_net
#> # A sfnetwork with 6 nodes and 5 edges
#> #
#> # CRS:  NA 
#> #
#> # A rooted tree with spatially explicit edges
#> #
#> # Node Data:     6 x 2 (active)
#> # Geometry type: POINT
#> # Dimension:     XY
#> # Bounding box:  xmin: 0 ymin: 0 xmax: 4 ymax: 2
#>      geom .tidygraph_node_index
#>   <POINT>                 <int>
#> 1   (0 1)                     1
#> 2   (3 1)                    NA
#> 3   (4 1)                     2
#> 4   (3 2)                     4
#> 5   (3 0)                     5
#> 6   (4 2)                     6
#> #
#> # Edge Data:     5 x 4
#> # Geometry type: LINESTRING
#> # Dimension:     XY
#> # Bounding box:  xmin: 0 ymin: 0 xmax: 4 ymax: 2
#>    from    to         geom .tidygraph_edge_index
#>   <int> <int> <LINESTRING>                 <int>
#> 1     1     2   (0 1, 3 1)                     1
#> 2     2     3   (3 1, 4 1)                     1
#> 3     4     2   (3 2, 3 1)                     2
#> # … with 2 more rows
plot(new_net)

Created on 2021-01-31 by the reprex package (v0.3.0)

Expected behavior Subdivide the edges but don't merge the equal nodes.

luukvdmeer commented 3 years ago

This is a quite unusual case, since normally you would not have several nodes at the same location. I'll mark it as low priority, but it is still a bug that needs to be fixed.