[GRASS-user] Forcing polyline nodes through a point

I am trying to create a map of hiking trails based on GPS data. If anyone can point me to a tutorial that discusses the techniques and issues involved, I would appreciate it. Meanwhile, a couple of specific questions.

I have a series of GPS tracks that have been brought into GRASS as polylines, and a series of time-averaged waypoints that have been brought into GRASS as points. The lines represent segments of color-blazed trails, and the waypoints represent higher-quality measurements of trail termini and intersections.

I am looking for a way to force the polylines (from GPS tracks) to terminate at the points (from averaged waypoints). One possibility would be to snap each terminal node to the nearest point (within a threshold), with the point coordinates taking precedence. I think I would prefer, instead, to have the point appended to the end of the line, becoming the new node (followed by a cleanup step with v.generalize).

Does anyone have any idea how I might accomplish either of these things? Is there a better/easier method?

With some up-front processing I could ensure that each trail segment terminates near an averaged waypoint. However, it would be considerably less work if I could automatically split a polyline at the vertex that is closest to a point (within a threshold) before processing as above. This would allow me to smooth (straighten) the trails while still maintaining sharp turns at important locations such as switchbacks in the trail.

Is this feasible?

Thanks, -Dwight

On May 28, 2009, at 10:04 PM, Dwight Needels wrote:

I am trying to create a map of hiking trails based on GPS data. If anyone can point me to a tutorial that discusses the techniques and issues involved, I would appreciate it. Meanwhile, a couple of specific questions.

I have a series of GPS tracks that have been brought into GRASS as polylines, and a series of time-averaged waypoints that have been brought into GRASS as points. The lines represent segments of color-blazed trails, and the waypoints represent higher-quality measurements of trail termini and intersections.

My questions were about how to force a vector line to pass exactly through specified points in such a way that they would continue to pass through those points after smoothing.

Thank you Hamish for pointing out several very useful tools for me to concentrate on learning. Also, thank you Moritz for the awk magic required to pipe point coordinates from one vector into the v.edit command operating on a second vector. With your indispensable help I was able to come up with something that does almost exactly what I want. If anybody can see any "gotchas" or better ways to accomplish these steps, I would appreciate the feedback.

Thanks, -Dwight

Starting with a line (track) vector and a point (waypoint) vector, modify the line vector so that it passes exactly through each point. This handles three cases; 1) where a vector line terminus undershoots the defined terminus point, 2) where a vector line terminus overshoots the defined terminus point, and 3) where the vector line passes within the threshold of a point somewhere in the middle of the line (a fork, hard curve or switchback).

Threshold (distance from points) should be chosen to include at least two vertices for each line segment of interest, without including vertices from other line segments.

Line vector: trail
Point vector: trail_nodes
Resulting line vector: trail_clean

Summary:
# Split the line vector at closest spot to each point within a threshold, delete superfluous points (v.net op=connect; v.edit tool=delete)
# Delete added lines and nodes to leave a gap (v.to.points -n; v.edit tool=vertexdel)
# Bridge the gaps, but have each bridge pass through one of the original points (v.distance -a; v.edit tool=copy)
# Remove zero length lines, merge bridges across the gaps in the line vector (v.clean tool=rmline; v.edit tool=merge)
# Add back a node at each of the original points, remove zero length lines (v.net op=connect; v.clean tool=rmline)
# Clean up intermediate vectors (g.remove)

Steps:
v.net trail points=trail_nodes out=trail_net op=connect thresh=100 --o
v.edit tool=delete map=trail_net layer=2 cats=1-9999
v.to.points -n in=trail_net out=trail_net_nodes --o
v.edit trail_net tool=vertexdel coords=`v.to.db -p trail_net_nodes layer=2 option=coor --quiet | awk -F"|" '{printf"%f,%f,",$2,$3} END{printf"\n"}'`
v.distance -p -a from=trail_nodes to=trail_net from_type=point to_type=line output=trail_bridges dmax=100 upload=dist column=dist --overwrite
v.edit map=trail_net tool=copy bgmap=trail_bridges ids=1-9999
v.clean input=trail_net output=trail_net_clean type=line tool=rmline thresh=-1 --o
v.edit tool=merge map=trail_net_clean ids=1-9999
v.net trail_net_clean points=trail_nodes out=trail_plus_nodes op=connect thresh=100 --o
v.clean input=trail_plus_nodes output=trail_clean type=line tool=rmline thresh=-1 --o
g.remove vect=trail_net,trail_net_clean,trail_bridges,trail_net_nodes,trail_plus_nodes

Nodes were added back (the polyline was split at each of the original points) so that the trail could be smoothed while still guaranteeing that the vector will pass through the original points.

# Smooth/straighten (v.generalize, method=snakes)
v.generalize input=trail_clean output=trail_smooth method=snakes alpha=1 beta=1 --o