查找 LatLng 坐标是否位于另外两个 LatLng 坐标之间

Find if a LatLng Coord is between two other LatLng Coords

本文关键字:坐标 LatLng 之间 两个 于另外 是否 查找      更新时间:2023-09-26

>Objective

了解坐标点是否位于其他两个坐标之间。

背景

我正在制作一个谷歌地图应用程序,我需要知道某个点是否在两个 LatLng 点(开始和结束)之间。

我正在寻找如下功能:

var currentCoord = {lat: 51.8732, lng: -118.6346};
var startCoord = {lat: 61.3434, lng: -118.0046};
var endCoord = {lat: 50.5468, lng: -118.5435};
function isBetween(startCoord, endCoord, currentCoord){
    //calculations here
    return "true if currentCoord is between startCoord and endCoord, or false otherwise";
}

我尝试了什么

为此,我阅读了几个问题和线程:

  • 检查线两点之间存在的坐标看起来很有希望,但由于它只针对网格中的X和Y点,并且没有考虑到地球曲率和其他方面,所以它不起作用。此外,它已关闭...
  • 检查两点之间的坐标点可能是我也在寻找的,但到目前为止它还没有答案,问题中的代码也不起作用。如果可能的话,我还想避免一连串的if陈述。
  • 检查投影在线段上的点是否不在外面,我也检查过,但不幸的是目标不同,我无法根据我正在寻找的内容调整答案。
  • 最后,http://www.movable-type.co.uk/scripts/latlong.html 是一个巨大的坐标资产库,但我看不出它们中的任何一个如何帮助我

法典

无论我尝试什么,我都无法让它工作,但我确实有一个关于我失败的实验的最小示例:

"use strict";
/*global google*/
function initialize() {
  let mapOptions = {
    zoom: 3,
    center: new google.maps.LatLng(0, -180),
    mapTypeId: google.maps.MapTypeId.TERRAIN
  };
  let map = new google.maps.Map(document.getElementById('map-canvas'),
    mapOptions);
  let flightPlanCoordinates = [
    new google.maps.LatLng(37.772323, -122.214897),
    new google.maps.LatLng(21.291982, -157.821856),
    new google.maps.LatLng(-18.142599, 178.431),
    new google.maps.LatLng(-27.46758, 153.027892)
  ];
  let flightPath = new google.maps.Polyline({
    path: flightPlanCoordinates,
    geodesic: true,
    strokeColor: '#FF0000',
    strokeOpacity: 1.0,
    strokeWeight: 2
  });
  flightPath.setMap(map);
  google.maps.event.addListener(flightPath, 'mouseover', function(event) {
    console.log("Marker is over the polyline");
  });
  let marker = new google.maps.Marker({
    position: new google.maps.LatLng(37.772323, -122.214897),
    draggable: true,
    map: map,
    title: 'Drag me!'
  });
  marker.addListener('drag', function(event) {
    let startPoint = {
      lat: 37.772323,
      lng: -122.214897
    };
    let endPoint = {
      lat: 21.291982,
      lng: -157.821856
    };
    let currentPoint = {
      lat: marker.getPosition().lat(),
      lng: marker.getPosition().lng()
    };
    if (checkCoordinate(startPoint, endPoint, currentPoint))
      console.log("in line !");
  });
}
google.maps.event.addDomListener(window, 'load', initialize);
function checkCoordinate(start, end, point) {
  var slope = (end.lng - start.lng) / (end.lat - start.lat);
  var newSlope = (end.lng - point.lng) / (end.lat - point.lat);
  return (point.lat > start.lat && point.lat < end.lat && point.lng > start.lng && point.lng < end.lng && slope == newSlope);
}
html,
body,
#map-canvas {
  height: 100%;
  margin: 0px;
  padding: 0px
}
<!DOCTYPE html>
<html>
<head>
  <meta name="viewport" content="initial-scale=1.0, user-scalable=no">
  <meta charset="utf-8">
  <title>Simple Polylines</title>
  <link rel="stylesheet" type="text/css" href="style.css">
  <script src="https://maps.googleapis.com/maps/api/js?v=3"></script>
  <script src="script.js" type="text/javascript"></script>
</head>
<body>
  <div id="map-canvas"></div>
</body>
</html>

问题

  • 如何使用数学方法确定给定坐标是否在两个坐标之间?

一种选择是使用 google.maps.geometry.poly.isLocationOnEdge 方法。

代码片段:

var map;
function initialize() {
  var mapOptions = {
    zoom: 2,
    center: new google.maps.LatLng(0, -180),
    mapTypeId: google.maps.MapTypeId.TERRAIN
  };
  map = new google.maps.Map(document.getElementById('map-canvas'),
    mapOptions);
  var flightPlanCoordinates = [
    new google.maps.LatLng(37.772323, -122.214897),
    new google.maps.LatLng(21.291982, -157.821856),
    new google.maps.LatLng(-18.142599, 178.431),
    new google.maps.LatLng(-27.46758, 153.027892)
  ];
  var flightPath = new google.maps.Polyline({
    path: flightPlanCoordinates,
    geodesic: false,
    strokeColor: '#FF0000',
    strokeOpacity: 1.0,
    strokeWeight: 2
  });
  flightPath.setMap(map);
  var marker = new google.maps.Marker({
    position: new google.maps.LatLng(37.772323, -122.214897),
    draggable: true,
    map: map,
    title: 'Drag me!'
  });
  marker.addListener('dragend', function(event) {
    var startPoint = {
      lat: 37.772323,
      lng: -122.214897
    };
    var startMarker = new google.maps.Marker({
      position: startPoint,
      map: map
    });
    var endPoint = {
      lat: 21.291982,
      lng: -157.821856
    };
    var endMarker = new google.maps.Marker({
      position: endPoint,
      map: map
    });
    var currentPoint = {
      lat: marker.getPosition().lat(),
      lng: marker.getPosition().lng()
    };
    if (checkCoordinate(startPoint, endPoint, marker.getPosition()))
      console.log("in line !");
  });
}
google.maps.event.addDomListener(window, 'load', initialize);
function checkCoordinate(start, end, point) {
  return google.maps.geometry.poly.isLocationOnEdge(point, new google.maps.Polyline({
    map: map,
    path: [start, end]
  }), 10e-1);
}
html,
body,
#map-canvas {
  height: 100%;
  margin: 0px;
  padding: 0px
}
<!DOCTYPE html>
<html>
<head>
  <meta name="viewport" content="initial-scale=1.0, user-scalable=no">
  <meta charset="utf-8">
  <title>Simple Polylines</title>
  <link rel="stylesheet" type="text/css" href="style.css">
  <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>
  <script src="script.js" type="text/javascript"></script>
</head>
<body>
  <div id="map-canvas"></div>
</body>
</html>

我已经找到了一个解决方案,通过计算一个点是否属于一条线。

研究了许多数学原理之后,我决定计算两点之间矩阵的行列式,并检查(以一定的精度)我的给定点是否在点 A 和 B 线之间。

/**
 * @const
 * @type        {Number}
 * @description The precision to calculate if a given point is between two other points. Low precisions get precise results but are less forgiving against errors.
 */
const PRECISION = 1;
/**
 * @function    isBetween
 * @description Determines if a point P = (p.x, p.y) lies on the line connecting points S = (S.x, S.y) and E = (E.x, E.y) by calculating the determinant of the matrix. A point is considered to belong to the line if the precision of the calculation is small enough (tests for errors and loss of precision).
 * @param       {Point} start   The start point
 * @param       {Point} end     The end point
 * @param       {Point} point   The point we which to test.
 * @returns     <code>true</code> if the given point belongs to the line, <code>false</code> otherwise.
 * @see         {@link http://stackoverflow.com/a/907491/1337392|Distance Matrix Calculation}
 */
function isBetween(start, end, point) {
    return Math.abs((end.lat - start.lat) * (point.lng - start.lng) - (end.lng - start.lng) * (point.lat - start.lat)) < PRECISION;
}

但是,此解决方案有一个值得一提的陷阱。这种解决方案的问题在于它没有考虑地球的曲率。它仅适用于直线。

因此,如果您正在检查城镇的距离,这根本不重要。但是,如果您正在检查穿越太平洋的航班,您可能应该使用另一种数学方法。

出于这个原因,并且由于折线已经考虑了地球的曲率,我决定使用geocodezip的答案。


PS:不得不说这很有趣。几个小时前,我回答了一个老问题,我也感谢geocodezip的深刻评论,现在他在这里回答我的问题。有时候,我确实相信世界是一个小地方。谢谢伙计!

使用 http://www.movable-type.co.uk/scripts/latlong.html 页面中的轴承部分,您可以检查

bearing(from currentCoord to startCoord) = 
  bearing(from currentCoord to endCoord) +/- 180 (with some tolerance)

这个方程说所有三个点都位于同一个大圆弧上

(我假设你的"在另外两个坐标之间"具有相同的含义)