Skip to content

Commit

Permalink
✨ Add function to split linestring by points
Browse files Browse the repository at this point in the history
  • Loading branch information
NONONOexe committed Aug 29, 2024
1 parent 19c56fd commit 86b0af6
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 3 deletions.
8 changes: 5 additions & 3 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ S3method(extract_segmented_network_nodes,road_network)
S3method(get_connected_links,road_network)
S3method(plot,road_network)
S3method(print,road_network)
S3method(split_line,LINESTRING)
S3method(split_linestring,LINESTRING)
S3method(summary,road_network)
export(bbox_to_polygon)
export(create_bbox)
Expand All @@ -20,10 +20,10 @@ export(extract_segmented_network_nodes)
export(filter_points_within_tolerance)
export(generate_ids)
export(get_connected_links)
export(is_linestring_endpoint)
export(osm_roads)
export(remove_points_near_endpoints)
export(sample_points_along_linestring)
export(split_line)
export(split_linestring)
export(transform_to_cartesian)
export(transform_to_geographic)
importFrom(igraph,"E<-")
Expand All @@ -40,9 +40,11 @@ importFrom(sf,st_as_sf)
importFrom(sf,st_boundary)
importFrom(sf,st_cast)
importFrom(sf,st_collection_extract)
importFrom(sf,st_contains)
importFrom(sf,st_coordinates)
importFrom(sf,st_crop)
importFrom(sf,st_crs)
importFrom(sf,st_distance)
importFrom(sf,st_equals)
importFrom(sf,st_intersection)
importFrom(sf,st_is_empty)
Expand Down
2 changes: 2 additions & 0 deletions R/pavement-package.R
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@
#' @importFrom sf st_boundary
#' @importFrom sf st_cast
#' @importFrom sf st_collection_extract
#' @importFrom sf st_contains
#' @importFrom sf st_coordinates
#' @importFrom sf st_crop
#' @importFrom sf st_crs
#' @importFrom sf st_distance
#' @importFrom sf st_equals
#' @importFrom sf st_intersection
#' @importFrom sf st_is_empty
Expand Down
88 changes: 88 additions & 0 deletions R/split-linestring.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#' Split a linestring into multiple segments
#'
#' @param linestring A linestring object.
#' @param split_points A `sfc` object containing points to split the
#' linestring.
#' @param tolerance A numeric value representing the maximum distance
#' allowed between the linestring and the split points. If the distance
#' between a split point and the linestring exceeds this value, the point
#' will not be used to split the linestring.
#' @return A `sfc` object containing the split linestrings.
#' @export
#' @examples
#' library(sf)
#'
#' # Create a linestring
#' linestring <- create_linestring(0, -1, 0, 1, 2, 1, 2, 0, 0, 0)
#'
#' # Create a set of split points
#' split_points <- st_sfc(
#' st_point(c(0, 0)),
#' st_point(c(1, 1)),
#' st_point(c(2, 0))
#' )
#'
#' # Plot the linestring and split points
#' plot(linestring)
#' plot(split_points, add = TRUE)
#'
#' # Split the linestring
#' segments <- split_linestring(linestring, split_points)
#'
#' # Plot the split linestrings
#' plot(segments, col = c("#E69F00", "#56B4E9", "#009E73", "#F0E442"), lwd = 2)
split_linestring <- function(linestring, split_points, tolerance = 0.01) {
UseMethod("split_linestring")
}

#' @export
split_linestring.LINESTRING <- function(linestring,
split_points,
tolerance = 0.01) {
# Decompose the linestring into a list of line segments
line_segments <- decompose_linestring(linestring)

# Identify split points on the line segments, remove those
# near the endpoints, and add the start point of each line
points_on_lines <- lapply(line_segments, function(line_segment) {
valid_points <- filter_points_within_tolerance(
split_points,
line_segment,
tolerance
)
valid_points <- remove_points_near_endpoints(
valid_points,
line_segment,
tolerance
)
c(st_startpoint(line_segment), valid_points)
})

# Combine all split points and add the end point of the linestring
all_points <- st_sfc(c(
unlist(points_on_lines, recursive = FALSE),
st_endpoint(linestring)
))

# Determine which points belong to each segment by calculating
# the segment index
is_split_point <- rep(FALSE, length(all_points))
is_split_point[unlist(st_contains(split_points, all_points))] <- TRUE
is_split_point[c(1, length(all_points))] <- FALSE
segment_index <- cumsum(is_split_point)

# Split the list of points into sub-lists based on the segment index
segment_points_list <- split(all_points, segment_index)
segment_points_list[-length(segment_points_list)] <- mapply(
c,
segment_points_list[-length(segment_points_list)],
lapply(all_points[is_split_point], st_sfc)
)

# Create linestring objects for each linestring segment
segments <- st_sfc(lapply(segment_points_list, function(segment_points) {
st_linestring(st_coordinates(segment_points))
}))

return(segments)
}
48 changes: 48 additions & 0 deletions man/split_linestring.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 86b0af6

Please sign in to comment.