r - How do I split/divide polyline shapefiles into equally-length-smaller segments? -


i have polyline shapefile, represents part of urban road network. shapefile contains several line/street segments (in case 58). using r-cran, further divide polyline segments smaller parts having equal length (e.g. 10 m).

to provide idea:

when import polyline shapefile r, , create dataframe, looks like:

# import polyline shapefile spatiallinesdataframe object: # library(sp) sp.roads <- readogr(dsn="/users/mgv/documents/project",layer="roads_sr_corr")   # create dataframe spatiallinesdataframe  # library(stplanr)     linedf <- line2df(sp.roads) str(linedf) > str(linedf) 'data.frame':   58 obs. of  4 variables:  $ fx: num  13.39991 13.40138 13.40606 13.40232 13.40177 ...  $ fy: num  42.35066 42.35412 42.35599 42.34514 42.34534 ...  $ tx: num  13.40150 13.40119 13.40591 13.40246 13.40182 ...  $ ty: num  42.35026 42.35386 42.35602 42.34530 42.34525 ... 

where (fx, fy, tx, ty) respectively longitudes , latitudes of points (x,y)_from, , (x,y)_to, delimiting each segment (here five).

the idea obtain denser polyline shapefile, can use spatial analyses "sort of grid" associate geo-referenced data points collected along roads each segment.

many help, , suggestion tackle issue.

the following function divides each line of spatial line object segments of split_length length plus leftover segment. uses vector notation of segment, creating vector u of unit length , direction of line split can multiplied create longer line composed of many segments (here , here references have used).

splitlines = function(spatial_line,                       split_length = 20,                       return.dataframe = f,                       plot.results = f) {   # function splits each line of spatial line object segments of given length   # spatial_line: spatial line object   # split_length: length of segments split lines into, in units of spatialline object   # return.dataframe: if true returns segments in form of dataframe, otherwise in spatialline object   # plot.results:    require(sp)   #### define support functions ####   # spatiallines2df extracts start , end point coordinates of each segment of spatialline object   # spatial_line: object class spatiallinesdataframe of package sp   spatiallines2df = function(spatial_line) {     df = data.frame(       id = character(),       mline_id = character(),       segment_id = character(),       fx = numeric(),       fy = numeric(),       tx = numeric(),       ty = numeric(),       stringsasfactors = false     )     (i in 1:length(spatial_line)) {       coords = spatial_line@lines[[i]]@lines[[1]]@coords # each line takes coords of vertex       row_nums = 1:(nrow(coords) - 1)       mline_id = formatc(i, width = 9, flag = '0') # creates id line       segment_id = formatc(row_nums, width = 3, flag = '0') # creates id each single segment belonging line       id = paste0(mline_id, '_', segment_id) # creates composite id       (j in row_nums) {         # each segment stores ids , coordinates         df[nrow(df) + 1, ] = c(id[j],                                mline_id,                                segment_id[j],                                coords[j, 1],                                coords[j, 2],                                coords[j + 1, 1],                                coords[j + 1, 2])       }     }     row.names(df) = null     df$fx = as.numeric(df$fx)     df$fy = as.numeric(df$fy)     df$tx = as.numeric(df$tx)     df$ty = as.numeric(df$ty)     return(df)   }    # linedf2spatiallines converts dataframe of ids , coordinates spatial line   # linedf: data.frame columns as:   #         id = generic ids of lines,   #         fx = coordinates x of first point of line   #         fy = coordinates y of first point of line   #         tx = coordinates x of second point of line   #         tx = coordinates y of second point of line    require(sp)   linedf2spatiallines = function(linedf) {     sl = list()     (i in 1:nrow(linedf)) {       c1 = cbind(rbind(linedf$fx[i], linedf$tx[i]),                  rbind(linedf$fy[i], linedf$ty[i]))       l1 = line(c1)       sl[[i]] = lines(list(l1), id = linedf$id[i])     }     sl = spatiallines(sl)     return(sl)   }     #### split lines ####   # convert input spatialline object dataframe , create empty output dataframe   linedf = spatiallines2df(spatial_line)   df = data.frame(     id = character(),     fx = numeric(),     fy = numeric(),     tx = numeric(),     ty = numeric(),     stringsasfactors = false   )     (i in 1:nrow(linedf)) {     # each line of dataframe, corresponding single line of spatial object     # skips if length less split_length     v_seg = linedf[i, ]     seg_length = sqrt((v_seg$fx - v_seg$tx) ^ 2 + (v_seg$fy - v_seg$ty) ^                         2) # segment length     if (seg_length <= split_length) {       df[nrow(df) + 1,] = c(paste0(v_seg$id, '_', '0000'),                             v_seg$fx,                             v_seg$fy,                             v_seg$tx,                             v_seg$ty)       next()     }     # create vector of direction line , unit length     # vector v corresponding line     v = c(v_seg$tx  -  v_seg$fx,           v_seg$ty  -  v_seg$fy)     # vector of direction v , unit length     u = c(v[1]  /  sqrt(v[1]  ^  2 + v[2]  ^  2), v[2]  /  sqrt(v[1]  ^  2 + v[2]  ^ 2))     # calculates how many segment line split , leftover     num_seg = floor(seg_length  /  split_length)     seg_left = seg_length - (num_seg  *  split_length)      # add output dataframe each segment plus leftover     (i in 0:(num_seg  -  1)) {       # add num_seg segments       df[nrow(df)  +  1,] = c(         paste0(v_seg$id, '_', formatc(i, width = 4, flag = '0')),         v_seg$fx + u[1]  *  split_length  *  i,         v_seg$fy + u[2]  *  split_length  *  i,         v_seg$fx + u[1]  *  split_length  *  (i  +  1),         v_seg$fy + u[2]  *  split_length  *  (i  +  1)       )     }     df[nrow(df) + 1,] = c(       paste0(v_seg$id, '_', formatc(         num_seg, width = 4, flag = '0'       )),       # add leftover segment       v_seg$fx + u[1] * split_length * num_seg,       v_seg$fy + u[2] * split_length * num_seg,       v_seg$tx,       v_seg$ty     )    }    #### visualise results check ####   if (plot.results) {     plot(spatial_line)     coords = cbind(as.numeric(df$fx), as.numeric(df$fy))     coords = rbind(coords, as.numeric(df$tx[nrow(df)]), as.numeric(df$ty)[nrow(df)])     sp_points = spatialpoints(coords)     plot(sp_points, col = 'red', add = t)   }    #### output ####   df$fx = as.numeric(df$fx)   df$fy = as.numeric(df$fy)   df$tx = as.numeric(df$tx)   df$ty = as.numeric(df$ty)   if (return.dataframe) {     return(df)   } # return dataframe   sl = linedf2spatiallines(df)   return(sl) # return spatialline object } 

you can test function following:

sl = spatiallines(list(lines(list(line(cbind(c(1,2,3, 4),c(3,2,2,4)))), id="a"))) plot(sl) sl_split = splitlines(sl, split_length = 0.1, return.dataframe = false, plot.results = true) 

i sure function can written in more concise , efficient way. have created package in git repository, in case contribute.


Comments