Skip to contents

Returns the subpath between two positions on one aggregate flowpath. An aggregate flowpath is the run of flowlines that share an aggregate_id and link end to end, such as an identified mainstem. A subpath is the part of it between two positions, each given as a flowline id and id_measure. The result lists the flowlines of the subpath from downstream to upstream, with the two end flowlines cut at the positions' measures. This is how to pull a stretch of river, such as the river between a gage and a confluence, out of any network that carries aggregate_id.

Both positions must be on the same aggregate flowpath. A stretch that crosses a confluence of two mainstems takes two calls, one for each mainstem, split at the confluence.

Support for cross-aggregate_id paths may be included in a future release.

Usage

get_subpath(from, to, x, snap_m = 0)

# S3 method for class 'data.frame'
get_subpath(from, to, x, snap_m = 0)

# S3 method for class 'hy'
get_subpath(from, to, x, snap_m = 0)

# S3 method for class 'hy_topo'
get_subpath(from, to, x, snap_m = 0)

# S3 method for class 'hy_node'
get_subpath(from, to, x, snap_m = 0)

Arguments

from

data.frame. One end of each subpath, with id and id_measure; the ends are unordered. An optional line_id column labels the output; without it the row number is used.

to

data.frame. The other end, row-aligned with from.

x

hy_topo or hy_node, or a data.frame coercible with hy(). Carries aggregate_id and length_km. A topo_sort column keeps building the aggregate flowpath axis cheap; without it a full topological sort is run.

snap_m

numeric. An end within this many meters of a flowline boundary snaps to it. Default 0.

Value

data.frame with line_id, segment_order (1 at the downstream end), id, id_from_measure, id_to_measure, length_km and reversed, one or more rows per subpath, plus piece geometry when x is sf and lwgeom is installed.

Details

from and to can be given in either order. Each position is converted to kilometers along the aggregate flowpath axis (the aggregate flowpath measured from its downstream end in x), and the subpath covers the kilometer span between the two. Pieces always come back downstream to upstream. If a from position is upstream of its to, reversed is TRUE on every row for that pair.

snap_m keeps small offsets from cutting slivers. An end within snap_m meters of a flowline boundary moves to that boundary before cutting, so a node a few meters inside a flowline does not leave a sliver, and two source flowlines that share a node share one cut. Zero-length pieces are dropped. If both ends land on one point after snapping, the result for that line_id is a single row with an NA id and zero length_km.

When x is sf and lwgeom is installed, each piece's geometry is cut with lwgeom::st_linesubstring() and attached.

Measures

id_measure is an interpolative measure along a single flowline: a percent of the line from its outlet, 0 at the outlet (downstream end) and 100 at the inlet (upstream, head end).

Examples

g <- sf::read_sf(system.file("extdata/new_hope.gpkg", package = "hydroloom"))
csv <- utils::read.csv(
  system.file("extdata/new_hope_mainstems.csv", package = "hydroloom"))

g$mainstemid <- csv$mainstem_uri[match(g$COMID, csv$comid)]
g$REACHCODE <- NULL

g <- sf::st_cast(g, "LINESTRING", warn = FALSE)

net <- add_toids(hy(g))

# flowlines of one mainstem, bottom and top by topo_sort
nh <- "https://geoconnex.us/ref/mainstems/2408056"
on_nh <- net[!is.na(net$aggregate_id) & net$aggregate_id == nh, ]

from <- data.frame(id = on_nh$id[which.min(on_nh$topo_sort)], id_measure = 0)
to <- data.frame(id = on_nh$id[which.max(on_nh$topo_sort)], id_measure = 100)

get_subpath(from, to, net)
#> Simple feature collection with 75 features and 7 fields
#> Geometry type: LINESTRING
#> Dimension:     XY
#> Bounding box:  xmin: 1496152 ymin: 1551922 xmax: 1516513 ymax: 1573365
#> Projected CRS: +proj=aea +lat_0=23 +lon_0=-96 +lat_1=29.5 +lat_2=45.5 +x_0=0 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs
#> # A tibble: 75 × 8
#>    line_id segment_order     id id_from_measure id_to_measure length_km reversed
#>      <int>         <int>  <int>           <dbl>         <dbl>     <dbl> <lgl>   
#>  1       1             1 8.90e6               0           100    1.39   FALSE   
#>  2       1             2 8.89e6               0           100    0.0450 FALSE   
#>  3       1             3 8.89e6               0           100    1.07   FALSE   
#>  4       1             4 8.89e6               0           100    0.507  FALSE   
#>  5       1             5 8.89e6               0           100    1.48   FALSE   
#>  6       1             6 8.89e6               0           100    2.33   FALSE   
#>  7       1             7 8.89e6               0           100    2.73   FALSE   
#>  8       1             8 8.89e6               0           100    0.343  FALSE   
#>  9       1             9 8.89e6               0           100    0.254  FALSE   
#> 10       1            10 8.89e6               0           100    0.0340 FALSE   
#> # ℹ 65 more rows
#> # ℹ 1 more variable: geometry <LINESTRING [m]>