0

I'm working on a project where I'm tracking user feedback for a section of construction, but it spans over a pretty long distance.

What I'd like to be able to happen is a user clicks the map, and the marker snaps to the road, somewhere between point A and point B. I've snapped markers to roads specifically, but never a specific road.

I feel like there are two potential approaches, either Google doesn't have this feature and I haven't found it yet.

Or, I create a polyline by generating directions from point A and point B, then somehow snap the marker to that polyline, something I'm not sure how to do just yet.

halfer
  • 19,824
  • 17
  • 99
  • 186
John Sly
  • 763
  • 1
  • 10
  • 31
  • 1
    This question/answer might be useful: [Confine dragging of Google Maps V3 Marker to Polyline](http://stackoverflow.com/questions/10694378/confine-dragging-of-google-maps-v3-marker-to-polyline) – geocodezip Jul 01 '14 at 16:43
  • I reworked that solution a little to fit my needs, but it doesn't really do it. That measures the distance from each point in a path, then grabs the closest point. I'd like something more seamless, that can grab the closest point in a path between two points in a path. – John Sly Jul 01 '14 at 20:14
  • 1
    Sorry it doesn't meet your needs. That solution assumes a polyline with points at a minimum distance (a "padded path"). I think I have code around somewhere that does what you want, it will take some time to dig it up. It came from a ported version of one of [Bill Chadwick's](http://www.bdcc.co.uk/Gmaps/BdccGmapBits.htm) libraries (the "DISTANCE POINT TO POLYLINE OR POLYGON" one) if I remember correctly. – geocodezip Jul 01 '14 at 21:21
  • After a LOT of digging, I did find a solution. I'm still weighing on how efficient it is. So far, it seems comparable to the solution above though. It breaks it down between each segment of the path, then gets the distance from the closest point in that path. – John Sly Jul 02 '14 at 14:54
  • I don't think there is any other way to do it. That is equivalent to the "padded" path in the linked example, just implemented on the segment of interest. – geocodezip Jul 02 '14 at 15:28

1 Answers1

0

My solution is a few levels of adaption from various sources. I liked the link above that pointed me towards padding the points, but in the end, it just didn't hit the accuracy I was hoping for. Remembering math class from way back when, I know it was possible to find this. In the end, this script cycles through the points in the path, then calculating the closest point between them to where the user clicked.

The inefficiency is that this has to loop through an entire set of points every time. Unfortunately, I just don't know a better way to do it, since a path of multiple points can move in any direction, there's no way to know until the end of the set whether or not you've found the closest point in the paths. The beauty of this is that it'll get the absolute closest point in the path, without snapping to anything.

The first parameter in this is the marker point. This is a single lat/lng pair. The second is the array of lat/lng points in your path. What it returns is the lat/lng on the path that comes closest to your individual point. If you wanted, this can be modified a lot to report more information, but for my purposes, this does exactly what I wanted it to do.

function find_closest_point_on_path(marker_pt,path_pts){

    var lowest = 9999999999999999;
    var theLat = 0;
    var theLng = 0;

    $.each(path_pts,function(key, path_pt){
        if(typeof path_pts[key+1] != "undefined"){
            var test = point_to_line_segment_distance(path_pt.lat(),path_pt.lng(), path_pts[key+1].lat(),path_pts[key+1].lng(), marker_pt.lat(),marker_pt.lng());
            if(test[0] < lowest){
                lowest = test[0];
                theLat = test[1];
                theLng = test[2];
            }
        }
    });

    return new google.maps.LatLng(theLat, theLng);
}

function point_to_line_segment_distance(startX,startY, endX,endY, pointX,pointY) {

    // Adapted from Philip Nicoletti's function, found here: http://www.codeguru.com/forum/printthread.php?t=194400

    r_numerator = (pointX - startX) * (endX - startX) + (pointY - startY) * (endY - startY);
    r_denominator = (endX - startX) * (endX - startX) + (endY - startY) * (endY - startY);
    r = r_numerator / r_denominator;

    px = startX + r * (endX - startX);
    py = startY + r * (endY - startY);

    s = ((startY-pointY) * (endX - startX) - (startX - pointX) * (endY - startY) ) / r_denominator;

    distanceLine = Math.abs(s) * Math.sqrt(r_denominator);

    closest_point_on_segment_X = px;
    closest_point_on_segment_Y = py;

    if ( (r >= 0) && (r <= 1) ) {
       distanceSegment = distanceLine;
    }
    else {
       dist1 = (pointX - startX) * (pointX - startX) + (pointY - startY) * (pointY - startY);
       dist2 = (pointX - endX) * (pointX - endX) + (pointY - endY) * (pointY - endY);
       if (dist1 < dist2) {
          closest_point_on_segment_X = startX;
          closest_point_on_segment_Y = startY;
          distanceSegment = Math.sqrt(dist1);
       }
       else {
          closest_point_on_segment_X = endX;
          closest_point_on_segment_Y = endY;
          distanceSegment = Math.sqrt(dist2);
       }
    }

    return [distanceSegment, closest_point_on_segment_X, closest_point_on_segment_Y];
}
halfer
  • 19,824
  • 17
  • 99
  • 186
John Sly
  • 763
  • 1
  • 10
  • 31