地理空间坐标和以千米为单位的距离

Dan*_*anM 14 geography distance geolocation geospatial

这是这个问题的后续内容.

我似乎被困在这上面了.基本上,我需要能够在标准度系统中来回转换为参考坐标,或者通过沿着国际日期线测量从南极向北的距离,然后从该日期的那个点开始向东的距离线.要做到这一点(以及一些更常见的距离测量的东西),我有一种方法来确定两个纬度/经度点之间的距离,另一种方法是采用纬度/经度点,航向和距离,并返回该课程结束时的纬度/经度点.

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

/* 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;
}
Run Code Online (Sandbox Code Playgroud)

这是我用来测试它的函数:

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;
}
Run Code Online (Sandbox Code Playgroud)

"end at"值应为appx.72.0/31.5.但相反,我得到大约1.25/0.021.

我认为我必须错过一些愚蠢的东西,忘记在某个地方转换单位,或者某些东西......任何帮助都将不胜感激!

更新1:

我(正确地)写了距离函数来返回米,但是在评论中误写了几公里......当我今天回到它时当然会让我感到困惑.无论如何,现在已经修复了,我已经修复了endOfCourse方法中的分解错误,并且我也意识到我也忘记了在该方法中从弧度转换回度数.无论如何:虽然看起来我现在得到正确的纬度数字(71.99 ......),但经度数是偏离的(我得到3.54而不是11.5).

更新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;
Run Code Online (Sandbox Code Playgroud)

Jon*_*ler 57

你在代码中有一个严重的神奇数字案例.表达方式:

 (60 * 1.1515 * 1.609344 * 1000)
Run Code Online (Sandbox Code Playgroud)

出现两次,但没有太多解释.在一些帮助下:1.609344是一英里的公里数; 60是学位的分钟数; 1000是一公里的米数; 和1.1515是海里的法定里程数(感谢DanM).一海里是赤道一分钟纬度的长度.

我假设你使用的是球形地球模型,而不是球形地球?代数不够复杂,不能是球形.

第一个公式 - 两个纬度和经度对之间的转换 - 是奇数.你需要delta-lat(Δλ)和delta-lon(Δφ)来解答答案.此外,对之间的距离:

(60° N, 30° W), (60° N, 60° W)
(60° N, 60° W), (60° N, 90° W)
Run Code Online (Sandbox Code Playgroud)

应该是相同的 - 但我很确定你的代码会产生不同的答案.

所以,我认为你需要回到你的球形三角学参考材料,看看你做错了什么.(我需要一段时间才能找到关于这个主题的书 - 它需要从它所在的任何一个盒子中解压缩.)

[ ...时间过去......拆包完成... ]

给定一个球面三角形,其顶点和侧面角度为A,B,C,a,b,c与这些顶点相对(即,a面从BC等),余弦公式为:

cos a = cos b . cos c + sin b . sin c . cos A
Run Code Online (Sandbox Code Playgroud)

将此应用于问题,我们可以调用给定BC的两个点,并且我们创建一个在A处具有直角的右球面三角形.

最糟糕的ASCII艺术:

                  + C
                 /|
                / |
            a  /  | b
              /   |
             /    |
            /     |
         B +------+ A
              c
Run Code Online (Sandbox Code Playgroud)

c等于经度差; b侧等于纬度差; 角度为90°,所以COS = 0.因此,相信的方程为一个是:

cos a = cos ?? . cos ?? + sin ?? . sin ?? . cos 90°

a = arccos (cos ?? . cos ??)
Run Code Online (Sandbox Code Playgroud)

然后通过乘以地球的半径将弧度中的角度α转换为距离.可替代地,给定一个以度(和一定程度的分数),则有60海里到一个程度,因此,60*1.1515法定英里,和60*1.1515*1.609344公里到一个程度.除非你想要以米为单位的距离,否则我认为不需要1000倍.

保罗·汤姆林(Pau​​l Tomblin)指出航空处方集v1.44作为等式的来源 - 事实上,它是存在的,并且当位置差异很小时,它还有更加数字稳定的版本.

进入基本三角学,我们也知道:

cos (A - B) = cos A . cos B + sin A . sin B
Run Code Online (Sandbox Code Playgroud)

在我给出的等式中应用两次可能最终得出航空处方集中的公式.

(我的参考文献:AE Roy和D Clarke撰写的"天文学:原理与实践,第四版" ;我的副本是1977年的第一版,Adam Hilger,ISBN 0-85274-346-7.)


NB退房(谷歌)'定义:'海里"'; 根据定义,似乎海里现在是1852米(1.852公里).乘数1.1515对应于海里的旧定义大约6080英尺.使用bc10的比例,我得到:

(1852/(3*0.3048))/1760
1.1507794480
Run Code Online (Sandbox Code Playgroud)

哪个因素适合您取决于您​​的基础.


从第一原理看第二个问题,我们的设置略有不同,我们需要'其他'球形三角函数方程,正弦公式:

sin A   sin B   sin C
----- = ----- = -----
sin a   sin b   sin c
Run Code Online (Sandbox Code Playgroud)

调整上图:

                  + C
                 /|
                / |
            a  /  | b
           |  /   |
           |X/    |
           |/     |
         B +------+ A
              c
Run Code Online (Sandbox Code Playgroud)

给出起点B,角度X = 90°-B,长度(角度)a,角度A = 90°.你所追求的是b(纬度的delta)和c(经度的delta).

所以,我们有:

sin a   sin b
----- = ----
sin A   sin B
Run Code Online (Sandbox Code Playgroud)

要么

        sin a . sin B
sin b = -------------
            sin A
Run Code Online (Sandbox Code Playgroud)

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

sin b = sin a . cos X
Run Code Online (Sandbox Code Playgroud)

这意味着你将行进的距离转换为角度a,取正弦值,乘以航向的余弦值,并取结果的反正弦值.

给定a,b(刚刚计算)和AB,我们可以应用余弦公式得到c.请注意,我们不能简单地重新应用正弦公式得到c,因为我们没有C的值,并且因为我们正在使用球面三角法,所以没有方便的规则C = 90° - B(总和球面三角形中的角度可以大于180°;考虑等边球面三角形,所有角度都等于90°,​​这是完全可行的).



小智 5

查看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; 
Run Code Online (Sandbox Code Playgroud)

请享用!