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
Post a Comment