如何计算路径上两点之间的距离?

How to calculate a distance between two points along a path?

我正在使用 openlayers3 并且我有编码的几何图形。我可以获得路径中所有点的坐标 (lat,lng)(每条路径大约 500 个点)。给定路径内的随机点,如何计算路径起点到该点之间的距离?

我看过 turfjs,它看起来很有前途,但我想象的使用它的解决方案并不是很好。取一个随机点 (p1),我可以找到距离 p1 最近的路径点 (p2),然后生成一个新的多边形并计算它的总距离。它可能有性能问题,尽管搜索将是 O(log n) 和新的多边形 O(n)。

编辑:随机点不一定在路径内,它是 GPS 坐标,存在误差范围。

编辑 2:对点数的估计是错误的,每条路径有大约 500 个点,而不是 5k

有人知道更好的方法吗?我对 openlayers3 和 turfjs 都不是很有经验。

正如您提到的,您正在使用 OpenLayers 3,我已经使用 OpenLayers 3 完成了一个示例,想法是:

  1. 得到Closest Point across the LineString给定坐标

  2. 遍历 LineString 点,计算每条路径的距离,看看我们最近的点是否与这条路径相交。

/* Let's Generate a Random LineString */

var length = 5000;

var minLongitude = Math.random()*-180 + 180;

var minLatitude = Math.random()*-90 + 90;

var wgs84Sphere = new ol.Sphere(6378137);

var lastPoint = [minLongitude, minLatitude]

var points = Array.from({ length })
.map( _ =>{
  var newPoint =  [
    Math.random() * (Math.random() > 0.8 ? -.005 : .005) + lastPoint[0]
    , Math.random() * (Math.random() > 0.2 ? -.005 : .005) + lastPoint[1]
  ]
  lastPoint = newPoint;
  return newPoint;
})

var distanceTotal = points
.reduce((dis, p, i)=>{
  if(points[i + 1])
    dis += wgs84Sphere.haversineDistance(p, points[i + 1] )
    return dis;          
}, 0);

console.log(distanceTotal)

var extent = new ol.extent.boundingExtent(points)

//console.log(points)

var lineString = new ol.Feature({
  geometry : new ol.geom.LineString(points)
});

var source = new ol.source.Vector();

var layer = new ol.layer.Vector({ source });

source.addFeature(lineString);


var map = new ol.Map({
  layers: [
    new ol.layer.Tile({
      source: new ol.source.OSM()
    })
  ],
  target: 'map',
  controls: ol.control.defaults({
    attributionOptions: /** @type {olx.control.AttributionOptions} */ ({
      collapsible: false
    })
  }),
  view: new ol.View({
    projection : 'EPSG:4326',
    center: [0, 0],
    zoom: 2
  })
});

map.addLayer(layer)
map.getView().fit(extent, map.getSize())

var auxLayer = new ol.layer.Vector({ source : new ol.source.Vector() })

var styleAux = new ol.style.Style({
  stroke: new ol.style.Stroke({
    color: 'green',
    width: 2
  })
});

var styleAuxLine = new ol.style.Style({
  stroke: new ol.style.Stroke({
    color: 'green',
    width: 0.5
  })
});

var styleAuxPoint = new ol.style.Style({
  image : new ol.style.Circle({
    radius: 5,
    fill: null,
    stroke: new ol.style.Stroke({color: 'black', width: 2})
  })
});

var styleAuxSourcePoint = new ol.style.Style({
  image : new ol.style.Circle({
    radius: 3,
    fill: null,
    stroke: new ol.style.Stroke({color: '#00bbff', width: 0.5})
  })
});

auxLayer.setStyle(function(f, r){
  var type = f.getGeometry().getType();
  if(type === 'LineString') return styleAux;
  return styleAuxPoint;
})

map.addLayer(auxLayer);

map.on('pointermove', function(e){
  if(e.dragging) return;
  var coord = e.coordinate;
  var distance = 0;

  var pointsGeometry = [];

  var sourcePointFeature = new ol.Feature({
    geometry : new ol.geom.Point(coord)
  });

  var closestPoint = lineString.getGeometry().getClosestPoint(coord);                
  var lineDiffFeature = new ol.Feature({
    geometry : new ol.geom.LineString([
      coord, closestPoint
    ])
  });
  for(let i = 0; i< points.length - 1; i++){
    var p = points[i]
    var next = points[i + 1];
    var subLineStringGeom = new ol.geom.LineString([ p, next ]);

    pointsGeometry.push(p);

    var e = 1e-10;
    var extent = [ closestPoint[0] - e, closestPoint[1] - e
                  , closestPoint[0] + e, closestPoint[1] + e
                 ]

    if(subLineStringGeom.intersectsExtent(extent)){
      //console.log(i);
      pointsGeometry.push(closestPoint);
      distance += wgs84Sphere.haversineDistance(p, closestPoint);
      break;
    }
    distance += wgs84Sphere.haversineDistance(p, next);
  }
  console.log(closestPoint)
  var cpGeometry = new ol.geom.Point(closestPoint);
  var cpFeature = new ol.Feature({ geometry : cpGeometry });

  var geometry = new ol.geom.LineString(pointsGeometry);
  var newFeature = new ol.Feature({ geometry });

  auxLayer.getSource().clear();
  auxLayer.getSource().refresh();

  auxLayer.getSource().addFeature(lineDiffFeature);
  auxLayer.getSource().addFeature(newFeature);
  auxLayer.getSource().addFeature(sourcePointFeature);
  auxLayer.getSource().addFeature(cpFeature);
  sourcePointFeature.setStyle(styleAuxSourcePoint);
  lineDiffFeature.setStyle(styleAuxLine);
  //console.log(geometry.getLength())
  console.log(distance);

})
html, body, #map {
  width : 100%;
  height : 100%;
  padding : 0px;
  margin : 0px;
}
<script src="https://openlayers.org/en/v3.20.1/build/ol.js"></script>
<link href="https://openlayers.org/en/v3.20.1/css/ol.css" rel="stylesheet"/>
<div id="map" class="map" tabindex="0"></div>