代码之家  ›  专栏  ›  技术社区  ›  DanM

地理空间坐标和距离(公里)

  •  14
  • DanM  · 技术社区  · 17 年前

    这是一个后续行动 this question

    我似乎被这件事缠住了。基本上,我需要能够来回转换参考标准度系统中的坐标,或者通过测量沿国际日期线从南极向北的距离,然后从日期线上的该点向东的距离。为了做到这一点(以及一些更通用的距离测量工具),我有一种方法来确定两个lat/lon点之间的距离,另一种方法是获取一个lat/lon点、一个航向和一个距离,并在课程结束时返回lat/lon点。

    以下是我定义的两个静态方法:

    /* Takes two lon/lat pairs and returns the distance between them in kilometers.
    */
    public static double distance (double lat1, double lon1, double lat2, double lon2) {
        double theta = toRadians(lon1-lon2);
        lat1 = toRadians(lat1);
        lon1 = toRadians(lon1);
        lat2 = toRadians(lat2);
        lon2 = toRadians(lon2);
    
        double dist = sin(lat1)*sin(lat2) + cos(lat1)*cos(lat2)*cos(theta);
        dist = toDegrees(acos(dist)) * 60 * 1.1515 * 1.609344 * 1000;
    
        return dist;
    }
    
    /* endOfCourse takes a lat/lon pair, a heading (in degrees clockwise from north), and a distance (in kilometers), and returns
     * the lat/lon pair that would be reached by traveling that distance in that direction from the given point.
     */
    public static double[] endOfCourse (double lat1, double lon1, double tc, double dist) {
        double pi = Math.PI;
        lat1 = toRadians(lat1);
        lon1 = toRadians(lon1);
        tc = toRadians(tc);
        double dist_radians = toRadians(dist / (60 * 1.1515 * 1.609344 * 1000));
        double lat = asin(sin(lat1) * cos(dist_radians) + cos(lat1) * sin(dist_radians) * cos(tc));
        double dlon = atan2(sin(tc) * sin(dist_radians) * cos(lat1), cos(dist_radians) - sin(lat1) * sin(lat));
        double lon = ((lon1-dlon + pi) % (2*pi)) - pi;
        double[] endPoint = new double[2];
        endPoint[0] = lat; endPoint[1] = lon;
        return endPoint;
    }
    

    下面是我用来测试它的函数:

    public static void main(String args[]) throws java.io.IOException, java.io.FileNotFoundException {
        double distNorth = distance(0.0, 0.0, 72.0, 0.0);
        double distEast = distance(72.0, 0.0, 72.0, 31.5);
        double lat1 = endOfCourse(0.0, 0.0, 0.0, distNorth)[0];
        double lon1 = endOfCourse(lat1, 0.0, 90.0, distEast)[1];
        System.out.println("end at: " + lat1 + " / " + lon1);
        return;
    }
    

    “结束于”值应为appx。72.0 / 31.5. 但是我得到的是大约1.25/0.021。

    我想我一定是错过了什么愚蠢的事情,忘了在什么地方转换单位,或者什么。。。任何帮助都将不胜感激!

    更新2: 我在测试中有一个打字错误,如下所述。它现在已在代码中修复。然而,经度数字仍然是错误的:我现在得到的是-11.34,而不是11.5。我想这些台词一定有问题:

    double dlon = atan2(sin(tc) * sin(dist_radians) * cos(lat1), cos(dist_radians) - sin(lat1) * sin(lat));
    double lon = ((lon1-dlon + pi) % (2*pi)) - pi;
    
    5 回复  |  直到 8 年前
        1
  •  60
  •   Pang Ajmal PraveeN    8 年前

    你的密码里有一个很严重的幻数。表达方式:

     (60 * 1.1515 * 1.609344 * 1000)
    

    出现两次,但没有太多的解释。借助一些帮助:1.609344是一英里中的公里数;60是度中的分钟数;1000是一公里中的米数;1.1515是一海里的法定英里数(谢谢,丹)。一海里是赤道纬度一分钟的长度。

    我假设您使用的是球形地球模型,而不是球形地球?代数不够复杂,不可能是球状的。

    第一个公式——两个纬度和经度对之间的转换——是奇数。您需要delta lat()和delta lon()来整理答案。此外,对之间的距离:

    (60° N, 30° W), (60° N, 60° W)
    (60° N, 60° W), (60° N, 90° W)
    

    所以,我认为你们需要回到你们的球面三角参考材料,看看你们做错了什么。(我需要一段时间才能找到关于这一主题的书——无论它在哪个盒子里,都需要把它打开。)

    …时间流逝…解包完成。。。 ]

    给定一个有角的球面三角形 B , C A. , , C A. 来自 C

    cos a = cos b . cos c + sin b . sin c . cos A
    

    将此应用于问题,我们可以称之为给定的两点 B A. .

                      + C
                     /|
                    / |
                a  /  | b
                  /   |
                 /    |
                /     |
             B +------+ A
                  c
    

    侧面 C 等于经度差;侧面 等于纬度差;角度 是90度,所以cos A. = 0. 因此,我相信 是:

    cos a = cos Δλ . cos Δφ + sin Δλ . sin Δφ . cos 90°
    
    a = arccos (cos Δλ . cos Δφ)
    

    A. 然后,以弧度为单位,乘以地球半径,转换为距离。或者,给定 A.

    Aviation Formulary v1.44 作为方程的一个来源——事实上,它是存在的,当位置差很小时,它还有一个数值上更稳定的版本。

    关于基本三角,我们也知道:

    cos (A - B) = cos A . cos B + sin A . sin B
    

    "Astronomy: Principles and Practice, Fourth Edition" A E Roy和D Clarke(2003年);我的副本是1977年的第一版,Adam Hilger,ISBN 0-85274-346-7。)


    bc 用10分制,我得到:

    (1852/(3*0.3048))/1760
    1.1507794480
    

    哪个因素对你有效取决于你的基础是什么。


    从第一原理来看第二个问题,我们有一个稍微不同的设置,我们需要“其他”球面三角方程,正弦公式:

    sin A   sin B   sin C
    ----- = ----- = -----
    sin a   sin b   sin c
    

    调整前一个图表:

                      + C
                     /|
                    / |
                a  /  | b
               |  /   |
               |X/    |
               |/     |
             B +------+ A
                  c
    

    给你一个起点 =90-B,长度(角度) A. ,和角度 A. (纬度上的三角洲)和 C (经度的增量)。

    因此,我们有:

    sin a   sin b
    ----- = ----
    sin A   sin B
    

            sin a . sin B
    sin b = -------------
                sin A
    

    或者,由于A=90°,sina=1,sinb=sin(90°-X)=cos X:

    sin b = sin a . cos X
    

    A.

    A. , B (刚刚计算)和 A. B C . 请注意,我们不能简单地重新应用正弦公式来获得 因为我们没有 C 而且,因为我们在玩球面三角学,没有方便的规则,C=90°-B(球面三角形中的角度之和可以大于180°;考虑一个等角球面三角形,所有角度等于90°,这是完全可行的)。


        2
  •  6
  •   Cjxcz Odjcayrwl    12 年前

    http://www.movable-type.co.uk/scripts/latlong.html

    该网站有许多不同的公式和Javascript代码,可以帮助您解决问题。我已经成功地将其翻译成C#和SQL Server UDF,并且我到处都在使用它们。

    例如,Javascript计算距离:

    var R = 6371; // km
    var φ1 = lat1.toRadians();
    var φ2 = lat2.toRadians();
    var Δφ = (lat2-lat1).toRadians();
    var Δλ = (lon2-lon1).toRadians();
    
    var a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
            Math.cos(φ1) * Math.cos(φ2) *
            Math.sin(Δλ/2) * Math.sin(Δλ/2);
    var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    
    var d = R * c; 
    

    享受

        3
  •  2
  •   Paul Tomblin    17 年前

       nm = km /  (1.1515 * 1.609344);
       deg = nm / 60;
       rad = toRadians(deg);
    

    换句话说,我认为你的差距是1000倍。

        4
  •  1
  •   Paul Tomblin    17 年前

    关于你最新的问题:不应该

    double lon1 = endOfCourse(lat1, 0.0, 90.0, distEast)[0];
    

    double lon1 = endOfCourse(lat1, 0.0, 90.0, distEast)[1];
    
        5
  •  0
  •   DanM    17 年前

    除了其他答案和更新中提到的实现错误之外,我还发现了这些公式的大问题。

    然而 ,位于同一平行线上(纬度线)的两点之间的大圆距离与直接沿纬度线旅行时的两点之间的距离不同,除非你在赤道上。

    因此:功能正常工作;然而,我在原始问题中提出的替代坐标系要求我们只看沿IDL向北的距离,然后看沿平行线在结果纬度处向东的距离。计算沿特定平行线的距离与计算沿大圆的距离是完全不同的!