将距离添加到 GPS 坐标

Posted

技术标签:

【中文标题】将距离添加到 GPS 坐标【英文标题】:Adding distance to a GPS coordinate 【发布时间】:2010-05-15 08:56:13 【问题描述】:

我正在尝试使用 GPS 在距固定点随机距离处生成一些点。

如何将距离以米为单位添加到 GPS 坐标? 我查看了 UTM 到 GPS 的转换,但有没有更简单的方法来实现这一点?

我在 android 平台上工作以防万一。

干杯, fgs

【问题讨论】:

【参考方案1】: P0(lat0,lon0):初始位置(单位:) dx,dy : 从你的初始位置随机偏移

您可以使用近似值来计算随机位置的位置:

 lat = lat0 + (180/pi)*(dy/6378137)
 lon = lon0 + (180/pi)*(dx/6378137)/cos(lat0)

只要随机距离偏移在 10-100 公里以下,这是相当精确的

编辑:当然,在 Java 中 Math.cos() 需要弧度,所以如果 lat0 是上面假设的度数,请使用 Math.cos(Math.PI/180.0*lat0)

【讨论】:

嗨,6378137是地球的半径吗?谢谢! 是(一如既往地以米为单位)。更准确地说,它是 WGS84 椭球的半长轴,也就是地球在赤道处的半径。 这不太适合我。经度偏移量总是应有的两倍。将其更改为以下更正:` lat = lat0 + (180/pi)*(dy/6378137) lon = lon0 + (180/pi/2)*(dx/6378137)/cos(lat0) ` 我可能会使用 6371.0 KM 的平均半径而不是赤道的半径。赔率是您引用的区域位于半长轴和半短轴之间。如果您需要更高的精度,请使用椭圆体的 Vincenty 公式 movable-type.co.uk/scripts/latlong-vincenty.html 偏移500-550km怎么办?【参考方案2】:

要取一个正方形,我正在使用这个:

 private double[] getBoundingBox(final double pLatitude, final double pLongitude, final int pDistanceInMeters) 

    final double[] boundingBox = new double[4];

    final double latRadian = Math.toRadians(pLatitude);

    final double degLatKm = 110.574235;
    final double degLongKm = 110.572833 * Math.cos(latRadian);
    final double deltaLat = pDistanceInMeters / 1000.0 / degLatKm;
    final double deltaLong = pDistanceInMeters / 1000.0 / degLongKm;

    final double minLat = pLatitude - deltaLat;
    final double minLong = pLongitude - deltaLong;
    final double maxLat = pLatitude + deltaLat;
    final double maxLong = pLongitude + deltaLong;

    boundingBox[0] = minLat;
    boundingBox[1] = minLong;
    boundingBox[2] = maxLat;
    boundingBox[3] = maxLong;

    return boundingBox;

这将返回一个包含 4 个坐标的数组,您可以使用它们制作一个以原始点为中心的正方形。

【讨论】:

效果很好。pDistanceInMeters 在这里是“半径”。 什么是 110.574235?我有一个 180 的方位角和两个坐标之间的距离差异。如何使用它在边界框中获得一个点? 什么是 110.574235? 赤道纬度到公里的换算系数【参考方案3】:

详细的大纲在http://www.movable-type.co.uk/scripts/latlong.html给出。

如果您在某处需要将经度/纬度相互转换为 UTM 坐标(GPS 中使用的坐标),您可能需要查看 http://www.uwgb.edu/dutchs/UsefulData/UTMFormulas.htm

【讨论】:

嗨!非常感谢,链接确实是我需要的。谢谢你。 :D【参考方案4】:

如果你想向东或向北或向西或向南,你可以使用这个:

@SuppressLint("DefaultLocale")
public static double go_mock_loc(double xx_lat,double xx_long,double xx_dinstance,String Direction)

//  double xx_lat= 45.815005; 
//  double xx_long= 15.978501;

//  int xx_dinstance=500;

    int equator_circumference=6371000;
    int polar_circumference=6356800;

    double m_per_deg_long =  360 / polar_circumference;
    double rad_lat=(xx_lat* (Math.PI) / 180);
    double m_per_deg_lat = 360 / ( Math.cos(rad_lat) * equator_circumference);

    double deg_diff_long = xx_dinstance * m_per_deg_long;
    double deg_diff_lat  = xx_dinstance * m_per_deg_lat; 


    double xx_north_lat = xx_lat + deg_diff_long;
    //double xx_north_long= xx_long;
    double xx_south_lat = xx_lat - deg_diff_long;
    //double xx_south_long= xx_long;

    //double xx_east_lat = xx_lat;
    double xx_east_long= xx_long + deg_diff_lat;  
    //double xx_west_lat = xx_lat;
    double xx_west_long= xx_long - deg_diff_lat;

    if (Direction.toUpperCase().contains("NORTH")) 
        return xx_north_lat;
     else if (Direction.toUpperCase().contains("SOUTH"))
    
        return xx_south_lat;
     else if (Direction.toUpperCase().contains("EAST"))
    
        return xx_east_long;
     else if (Direction.toUpperCase().contains("WEST"))
    
        return xx_west_long;
    
    else 
        return 0; 


【讨论】:

很容易移植到 c#【参考方案5】:

用 Kotlin 重写 @Ersin Gülbahar 的答案:

object LocationUtil 

enum class Direction 
    NORTH, SOUTH, EAST, WEST


fun addDistanceInMeters(
    latitude: Double,
    longitude: Double,
    distanceInMeters: Int,
    direction: Direction
): Pair<Double, Double> 
    val equatorCircumference = 6371000
    val polarCircumference = 6356800

    val mPerDegLong = (360 / polarCircumference.toDouble())
    val radLat = latitude * Math.PI / 180
    val mPerDegLat = 360 / (Math.cos(radLat) * equatorCircumference)

    val degDiffLong = distanceInMeters * mPerDegLong
    val degDiffLat = distanceInMeters * mPerDegLat

    val xxNorthLat = latitude + degDiffLong
    val xxSouthLat = latitude - degDiffLong
    val xxEastLong = longitude + degDiffLat
    val xxWestLong = longitude - degDiffLat

    return when (direction) 
        Direction.NORTH -> Pair(xxNorthLat, longitude)
        Direction.SOUTH -> Pair(xxSouthLat, longitude)
        Direction.EAST -> Pair(latitude, xxEastLong)
        Direction.WEST -> Pair(latitude, xxWestLong)
    

【讨论】:

【参考方案6】:

我发现 @Bogdan Khrystov 的解决方案非常好。 所以这是他的解决方案的 C# 版本。

public enum GeoDirection

   NORTH = 1, SOUTH = 2, EAST = 3, WEST = 4
            
    
public static Tuple<double, double> AddDistanceInMeters(double latitude, double longitude, int distanceInMeters, GeoDirection direction)

  var equatorCircumference = 6371000;
  var polarCircumference = 6356800;
    
  var mPerDegLong = 360 / (double)polarCircumference;
  var radLat = latitude * Math.PI / 180;
  var mPerDegLat = 360 / (Math.Cos(radLat) * equatorCircumference);
    
  var degDiffLong = distanceInMeters * mPerDegLong;
  var degDiffLat = distanceInMeters * mPerDegLat;
    
  var xxNorthLat = latitude + degDiffLong;
  var xxSouthLat = latitude - degDiffLong;
  var xxEastLong = longitude + degDiffLat;
  var xxWestLong = longitude - degDiffLat;
    
  switch (direction)
  
    case GeoDirection.NORTH:
       return new Tuple<double, double>(xxNorthLat, longitude);
    case GeoDirection.SOUTH:
       return new Tuple<double, double>(xxSouthLat, longitude);
    case GeoDirection.EAST:
       return new Tuple<double, double>(latitude, xxEastLong);
    case GeoDirection.WEST:
       return new Tuple<double, double>(latitude, xxWestLong);
    default:
       return null;
    

【讨论】:

【参考方案7】:

此代码将两个坐标之间的线分成 n 段。将增量计算替换为您的固定距离

 @Override
public void split(Coordinates p1, Coordinates p2, int segments) 
    double φ1 = Math.toRadians(p1.getLat());
    double λ1 = Math.toRadians(p1.getLon());
    double φ2 = Math.toRadians(p2.getLat());
    double λ2 = Math.toRadians(p2.getLon());


    double xDelta = (φ2 - φ1) / segments;
    double yDelta = (λ2 - λ1) / segments;
    for (int i = 0; i < segments; i++)
        double x = φ1 + i * xDelta;
        double y = λ1 + i * yDelta;
        double xc = Math.toDegrees(x);
        double yc = Math.toDegrees(y);
        System.out.println(xc+","+yc);
    

【讨论】:

【参考方案8】:

结合上面@Ersin Gülbahar 和@Stéphane 的答案,我在Flutter/Dart 中提出了这个解决方案:

import 'dart:math' as math;
enum Direction  north, south, east, west 

double moveCoordinate(
    double latitude, double longitude, double distanceToMoveInMeters, Direction directionToMove) 
  const earthEquatorRadius = 6378137;
  final latitudeOffset = (180 / math.pi) * (distanceToMoveInMeters / earthEquatorRadius);
  final longitudeOffset = (180 / math.pi) *
      (distanceToMoveInMeters / earthEquatorRadius) /
      math.cos(math.pi / 180 * latitude);

  switch (directionToMove) 
    case Direction.north:
      return latitude + latitudeOffset;
    case Direction.south:
      return latitude - latitudeOffset;
    case Direction.east:
      return longitude + longitudeOffset;
    case Direction.west:
      return longitude - longitudeOffset;
  

  return 0;

【讨论】:

【参考方案9】:

这行得通,经过测试。代码是 C#,但您可以轻松地将其更改为另一种语言

 private PointLatLng NewPositionBasedOnDistanceAngle(PointLatLng org, double distance, double bearing)
 
    double rad = bearing * Math.PI / 180; //to radians
    double lat1 = org.Lat * Math.PI / 180; //to radians
    double lng1 = org.Lng * Math.PI / 180; //to radians
    double lat = Math.Asin(Math.Sin(lat1) * Math.Cos(distance / 6378137) + Math.Cos(lat1) * Math.Sin(distance / 6378137) * Math.Cos(rad));
    double lng = lng1 + Math.Atan2(Math.Sin(rad) * Math.Sin(distance / 6378137) * Math.Cos(lat1), Math.Cos(distance / 6378137) - Math.Sin(lat1) * Math.Sin(lat));
    return new PointLatLng(lat * 180 / Math.PI, lng * 180 / Math.PI); // to degrees  
 

【讨论】:

以上是关于将距离添加到 GPS 坐标的主要内容,如果未能解决你的问题,请参考以下文章

将gps坐标转换为距离并将距离转换为十进制度数的半径

计算从一个 GPS 坐标到另一个坐标的距离?

基于与给定点的距离的最近 GPS 坐标

使用 GPS 坐标计算最短距离

GPS已知首尾坐标 如何求距离

用墨卡托和GPS坐标计算距离时误差测试