如何使用谷歌地图API计算从已知点到最近点的距离

How to calculate the distance from a known point to the closest point in a route using Google Maps API

本文关键字:最近 距离 谷歌地图 何使用 API 计算      更新时间:2023-09-26

我正在做一个项目,显示有多条路线的地图。我需要能够通过一个地址搜索,并返回到每条路线中最近点的距离。测量从已知点到最近点的距离很容易,但我需要知道从已知点到最近点的距离。

这是一个代码,它绘制了3条路线和一个半径为50km的圆圈。我需要在每条路线上从那个点测量到最近的点。

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<meta charset="utf-8" />
<title>Waypoints in directions</title>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" />
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap-theme.min.css" />
<!-- Latest compiled and minified JavaScript -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
<style>
html, body, #map-canvas {
    height: 100%;
    margin: 0px;
    padding: 0px
}
#map-canvas {
    float:left;
    width:70%;
    height:100%;
}
#panel {
    position: absolute;
    top: 5px;
    left: 50%;
    margin-left: -180px;
    z-index: 5;
    background-color: #fff;
    padding: 5px;
    border: 1px solid #999;
}
#control_panel {
    float:right;
    width:30%;
    text-align:left;
    padding-top:20px;
}
</style>
</head>
<body>
<div id="map-canvas"></div>
<div id="control_panel">
    <div class="container" style="width:auto;">
        <h1>Trips:</h1>

        <div class="panel panel-default">
            <div class="panel-heading">
                <h3 class="panel-title">Blue Run</h3>
            </div>
            <div class="panel-body">
                <ol>
<li><strong>Autosystems (University)</strong><br />300 University Ave, Plant 1 Belleville, ON K8N 5T7</li><li><strong>Fanuc America</strong><br />3900 West Hamlin Road Rochester Hills, MI 48309</li>                </ol>
            </div>
        </div>
        <div class="panel panel-default">
            <div class="panel-heading">
                <h3 class="panel-title">Big Run</h3>
            </div>
            <div class="panel-body">
                <ol>
<li><strong>Asyst Technologies</strong><br />5811 - 99th Avenue Kenosha, WI 53144</li><li><strong>Autosystems America Inc</strong><br />46600 Port St Plymouth, MI 48170</li>                </ol>
            </div>
        </div>
        <div class="panel panel-default">
            <div class="panel-heading">
                <h3 class="panel-title">Slow Run</h3>
            </div>
            <div class="panel-body">
                <ol>
<li><strong>A B Automation</strong><br />2155 North Talbot Road Windsor, ON N9A 6J3</li><li><strong>Autosystems America Inc</strong><br />46600 Port St Plymouth, MI 48170</li><li><strong>Industrial Automation</strong><br />2968 Waterview Rochester Hills, MI 48309</li><li><strong>Arkema Inc.</strong><br />4350 Campground Rd Louisville, KY 40216</li>                </ol>
            </div>
        </div>
    </div>
</div>
<input type="hidden" name="lat" id="lat" value="" />
<input type="hidden" name="lng" id="lng" value="" />
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=<api-key>"></script>
<script type="text/javascript">
// Initialize some variables
var directionsService = new google.maps.DirectionsService();
var num, map, data;
var requestArray = [], renderArray = [];
// A JSON Array containing some people/routes and the destinations/stops
var jsonArray = {
    "Blue Run": ["300 University Ave, Plant 1 Belleville, ON K8N 5T7","3900 West Hamlin Road Rochester Hills, MI 48309"],
    "Big Run": ["5811 - 99th Avenue Kenosha, WI 53144","46600 Port St Plymouth, MI 48170"],
    "Slow Run": ["2155 North Talbot Road Windsor, ON N9A 6J3","46600 Port St Plymouth, MI 48170","2968 Waterview Rochester Hills, MI 48309","4350 Campground Rd Louisville, KY 40216"]
}
// 16 Standard Colours for navigation polylines
var colourArray = ['navy', 'red', 'green', 'grey', 'fuchsia', 'black', 'white', 'lime', 'maroon', 'purple', 'aqua', 'silver', 'olive', 'blue', 'yellow', 'teal'];
// Let's make an array of requests which will become individual polylines on the map.
function generateRequests(){
    requestArray = [];
    for (var route in jsonArray){
        // This now deals with one of the people / routes
        // Somewhere to store the wayoints
        var waypts = [];
        // 'start' and 'finish' will be the routes origin and destination
        var start, finish
        // lastpoint is used to ensure that duplicate waypoints are stripped
        var lastpoint
        data = jsonArray[route]
        limit = data.length
        for (var waypoint = 0; waypoint < limit; waypoint++) {
            if (data[waypoint] === lastpoint){
                // Duplicate of of the last waypoint - don't bother
                continue;
            }
            // Prepare the lastpoint for the next loop
            lastpoint = data[waypoint]
            // Add this to waypoint to the array for making the request
            waypts.push({
                location: data[waypoint],
                stopover: true
            });
        }
        // Grab the first waypoint for the 'start' location
        start = (waypts.shift()).location;
        // Grab the last waypoint for use as a 'finish' location
        finish = waypts.pop();
        if(finish === undefined){
            // Unless there was no finish location for some reason?
            finish = start;
        } else {
            finish = finish.location;
        }
        // Let's create the Google Maps request object
        var request = {
            origin: start,
            destination: finish,
            waypoints: waypts,
            travelMode: google.maps.TravelMode.DRIVING
        };
        // and save it in our requestArray
        requestArray.push({"route": route, "request": request});
    }
    processRequests();
}
function processRequests(){
    // Counter to track request submission and process one at a time;
    var i = 0;
    // Used to submit the request 'i'
    function submitRequest(){
        directionsService.route(requestArray[i].request, directionResults);
    }
    // Used as callback for the above request for current 'i'
    function directionResults(result, status) {
        if (status == google.maps.DirectionsStatus.OK) {
            // Create a unique DirectionsRenderer 'i'
            renderArray[i] = new google.maps.DirectionsRenderer();
            renderArray[i].setMap(map);
            // Some unique options from the colorArray so we can see the routes
            renderArray[i].setOptions({
                preserveViewport: true,
                suppressInfoWindows: true,
                polylineOptions: {
                    strokeWeight: 4,
                    strokeOpacity: 0.8,
                    strokeColor: colourArray[i]
                },
                markerOptions:{
                    icon:{
                        path: google.maps.SymbolPath.BACKWARD_CLOSED_ARROW,
                        scale: 4,
                        strokeColor: colourArray[i]
                    },
                    clickable: true,
                    title: 'Boo yeah!'
                }
            });
            // Use this new renderer with the result
            renderArray[i].setDirections(result);
            // and start the next request
            nextRequest();
        }
    }
    function nextRequest(){
        // Increase the counter
        i++;
        // Make sure we are still waiting for a request
        if(i >= requestArray.length){
            // No more to do
            return;
        }
        // Submit another request
        submitRequest();
    }
    // This request is just to kick start the whole process
    submitRequest();
}
// Called Onload
function init() {
    var address = "320 Elizabeth St Midland, ON L4R 4L6";
    var geo = new google.maps.Geocoder;
    geo.geocode({'address':address},function(results, status){
        if (status == google.maps.GeocoderStatus.OK) {
            var latitude = results[0].geometry.location.lat();
            var longitude = results[0].geometry.location.lng();
            // Some basic map setup (from the API docs) 
            var mapOptions = {
                //center: new google.maps.LatLng(50.677965, -3.768841),
                center: new google.maps.LatLng(latitude, longitude),
                zoom: 10,
                mapTypeControl: true,
                streetViewControl: true,
                mapTypeId: google.maps.MapTypeId.ROADMAP,
                travelMode: google.maps.TravelMode.DRIVING,
                //unitSystem: google.maps.UnitSystem.IMPERIAL
                unitSystem: google.maps.UnitSystem.METRIC
            };
            map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
            var circle = {
                strokeColor: '#AA0000',
                strokeOpacity: 0.6,
                strokeWeight: 2,
                fillColor: '#CCCCCC',
                fillOpacity: 0.35,
                map: map,
                radius: 50000,
                center: new google.maps.LatLng(latitude, longitude)
            };
            var pickupSpot = new google.maps.Circle(circle);
            // Start the request making
            generateRequests()
        } else {
            alert("Geocode was not successful for the following reason: " + status);
        }
    });
}
// Get the ball rolling and trigger our init() on 'load'
google.maps.event.addDomListener(window, 'load', init);
</script>
</body>
</html>

我在网上找不到我需要的东西。有人能帮忙吗?

一个解决方案:

  1. 从每条路线提取折线
  2. 处理每条折线,找到最近的点(使用直线,"如乌鸦飞行"的距离)
// Use this new renderer with the result
renderArray[i].setDirections(result);
// and start the next request
var polyline = getPolyline(result);
var marker = new google.maps.Marker({
    position: getClosestPoint(referencePt, polyline),
    map: map,
    icon: iconArray[i]
});
nextRequest();

概念验证

代码片段:

var referencePt = "TBD";
// Initialize some variables
var directionsService = new google.maps.DirectionsService();
var num, map, data;
var requestArray = [],
  renderArray = [];
var markerBounds = new google.maps.LatLngBounds();
// A JSON Array containing some people/routes and the destinations/stops
var jsonArray = {
  "Blue Run": ["300 University Ave, Plant 1 Belleville, ON K8N 5T7", "3900 West Hamlin Road Rochester Hills, MI 48309"],
  "Big Run": ["5811 - 99th Avenue Kenosha, WI 53144", "46600 Port St Plymouth, MI 48170"],
  "Slow Run": ["2155 North Talbot Road Windsor, ON N9A 6J3", "46600 Port St Plymouth, MI 48170", "2968 Waterview Rochester Hills, MI 48309", "4350 Campground Rd Louisville, KY 40216"]
}
// 16 Standard Colours for navigation polylines
var colourArray = ['navy', 'red', 'green', 'grey', 'fuchsia', 'black', 'white', 'lime', 'maroon', 'purple', 'aqua', 'silver', 'olive', 'blue', 'yellow', 'teal'];
var iconArray = [
  "http://maps.google.com/mapfiles/ms/icons/blue.png",
  "http://maps.google.com/mapfiles/ms/icons/red.png",
  "http://maps.google.com/mapfiles/ms/icons/green.png"
];
// Let's make an array of requests which will become individual polylines on the map.
function generateRequests() {
  requestArray = [];
  for (var route in jsonArray) {
    // This now deals with one of the people / routes
    // Somewhere to store the wayoints
    var waypts = [];
    // 'start' and 'finish' will be the routes origin and destination
    var start, finish
    // lastpoint is used to ensure that duplicate waypoints are stripped
    var lastpoint
    data = jsonArray[route]
    limit = data.length
    for (var waypoint = 0; waypoint < limit; waypoint++) {
      if (data[waypoint] === lastpoint) {
        // Duplicate of of the last waypoint - don't bother
        continue;
      }
      // Prepare the lastpoint for the next loop
      lastpoint = data[waypoint]
      // Add this to waypoint to the array for making the request
      waypts.push({
        location: data[waypoint],
        stopover: true
      });
    }
    // Grab the first waypoint for the 'start' location
    start = (waypts.shift()).location;
    // Grab the last waypoint for use as a 'finish' location
    finish = waypts.pop();
    if (finish === undefined) {
      // Unless there was no finish location for some reason?
      finish = start;
    } else {
      finish = finish.location;
    }
    // Let's create the Google Maps request object
    var request = {
      origin: start,
      destination: finish,
      waypoints: waypts,
      travelMode: google.maps.TravelMode.DRIVING
    };
    // and save it in our requestArray
    requestArray.push({
      "route": route,
      "request": request
    });
  }
  processRequests();
}
function processRequests() {
  // Counter to track request submission and process one at a time;
  var i = 0;
  // Used to submit the request 'i'
  function submitRequest() {
    directionsService.route(requestArray[i].request, directionResults);
  }
  // Used as callback for the above request for current 'i'
  function directionResults(result, status) {
    if (status == google.maps.DirectionsStatus.OK) {
      // Create a unique DirectionsRenderer 'i'
      renderArray[i] = new google.maps.DirectionsRenderer();
      renderArray[i].setMap(map);
      // Some unique options from the colorArray so we can see the routes
      renderArray[i].setOptions({
        preserveViewport: true,
        suppressInfoWindows: true,
        polylineOptions: {
          strokeWeight: 4,
          strokeOpacity: 0.8,
          strokeColor: colourArray[i]
        },
        markerOptions: {
          icon: {
            path: google.maps.SymbolPath.BACKWARD_CLOSED_ARROW,
            scale: 4,
            strokeColor: colourArray[i]
          },
          clickable: true,
          title: 'Boo yeah!'
        }
      });
      // Use this new renderer with the result
      renderArray[i].setDirections(result);
      // and start the next request
      var polyline = getPolyline(result);
      var marker = new google.maps.Marker({
        position: getClosestPoint(referencePt, polyline),
        map: map,
        icon: iconArray[i]
      });
      markerBounds.extend(marker.getPosition());
      nextRequest();
    }
  }
  function nextRequest() {
    // Increase the counter
    i++;
    // Make sure we are still waiting for a request
    if (i >= requestArray.length) {
      map.fitBounds(markerBounds);
      // No more to do
      return;
    }
    // Submit another request
    submitRequest();
  }
  // This request is just to kick start the whole process
  submitRequest();
}
function getPolyline(result) {
  var polyline = new google.maps.Polyline({
    path: []
  });
  var path = result.routes[0].overview_path;
  var legs = result.routes[0].legs;
  for (i = 0; i < legs.length; i++) {
    var steps = legs[i].steps;
    for (j = 0; j < steps.length; j++) {
      var nextSegment = steps[j].path;
      for (k = 0; k < nextSegment.length; k++) {
        polyline.getPath().push(nextSegment[k]);
      }
    }
  }
  return polyline;
}
function getClosestPoint(point, polyline) {
  var closestDistance = Number.MAX_VALUE;
  var closestPt;
  for (var i = 0; i < polyline.getPath().getLength(); i++) {
    var distance = google.maps.geometry.spherical.computeDistanceBetween(point, polyline.getPath().getAt(i));
    if (distance < closestDistance) {
      closestDistance = distance;
      closestPt = polyline.getPath().getAt(i);
    }
  }
  return closestPt;
}
// Called Onload
function init() {
  var address = "320 Elizabeth St Midland, ON L4R 4L6";
  var geo = new google.maps.Geocoder;
  geo.geocode({
    'address': address
  }, function(results, status) {
    if (status == google.maps.GeocoderStatus.OK) {
      var latitude = results[0].geometry.location.lat();
      var longitude = results[0].geometry.location.lng();
      // Some basic map setup (from the API docs) 
      var mapOptions = {
        //center: new google.maps.LatLng(50.677965, -3.768841),
        center: new google.maps.LatLng(latitude, longitude),
        zoom: 10,
        mapTypeControl: true,
        streetViewControl: true,
        mapTypeId: google.maps.MapTypeId.ROADMAP,
        travelMode: google.maps.TravelMode.DRIVING,
        //unitSystem: google.maps.UnitSystem.IMPERIAL
        unitSystem: google.maps.UnitSystem.METRIC
      };
      map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
      var circle = {
        strokeColor: '#AA0000',
        strokeOpacity: 0.6,
        strokeWeight: 2,
        fillColor: '#CCCCCC',
        fillOpacity: 0.35,
        map: map,
        radius: 50000,
        center: new google.maps.LatLng(latitude, longitude)
      };
      referencePt = mapOptions.center;
      var pickupSpot = new google.maps.Circle(circle);
      // Start the request making
      generateRequests()
    } else {
      alert("Geocode was not successful for the following reason: " + status);
    }
  });
}
// Get the ball rolling and trigger our init() on 'load'
google.maps.event.addDomListener(window, 'load', init);
html,
body,
#map-canvas {
  height: 100%;
  margin: 0px;
  padding: 0px
}
#map-canvas {
  float: left;
  width: 70%;
  height: 100%;
}
#panel {
  position: absolute;
  top: 5px;
  left: 50%;
  margin-left: -180px;
  z-index: 5;
  background-color: #fff;
  padding: 5px;
  border: 1px solid #999;
}
#control_panel {
  float: right;
  width: 30%;
  text-align: left;
  padding-top: 20px;
}
<script src="https://maps.googleapis.com/maps/api/js?libraries=geometry"></script>
<div id="map-canvas"></div>
<div id="control_panel">
  <div class="container" style="width:auto;">
    <h1>Trips:</h1>
    <div class="panel panel-default">
      <div class="panel-heading">
        <h3 class="panel-title">Blue Run</h3>
      </div>
      <div class="panel-body">
        <ol>
          <li><strong>Autosystems (University)</strong>
            <br />300 University Ave, Plant 1 Belleville, ON K8N 5T7</li>
          <li><strong>Fanuc America</strong>
            <br />3900 West Hamlin Road Rochester Hills, MI 48309</li>
        </ol>
      </div>
    </div>
    <div class="panel panel-default">
      <div class="panel-heading">
        <h3 class="panel-title">Big Run</h3>
      </div>
      <div class="panel-body">
        <ol>
          <li><strong>Asyst Technologies</strong>
            <br />5811 - 99th Avenue Kenosha, WI 53144</li>
          <li><strong>Autosystems America Inc</strong>
            <br />46600 Port St Plymouth, MI 48170</li>
        </ol>
      </div>
    </div>
    <div class="panel panel-default">
      <div class="panel-heading">
        <h3 class="panel-title">Slow Run</h3>
      </div>
      <div class="panel-body">
        <ol>
          <li><strong>A B Automation</strong>
            <br />2155 North Talbot Road Windsor, ON N9A 6J3</li>
          <li><strong>Autosystems America Inc</strong>
            <br />46600 Port St Plymouth, MI 48170</li>
          <li><strong>Industrial Automation</strong>
            <br />2968 Waterview Rochester Hills, MI 48309</li>
          <li><strong>Arkema Inc.</strong>
            <br />4350 Campground Rd Louisville, KY 40216</li>
        </ol>
      </div>
    </div>
  </div>
</div>
<input type="hidden" name="lat" id="lat" value="" />
<input type="hidden" name="lng" id="lng" value="" />