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

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

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

为了以防万一,我正在使用 Android 平台。

干杯, fgs

【问题讨论】:

    标签: c# android gps


    【解决方案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  
             }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多