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

将米转换为十进制度数

  •  11
  • Peter  · 技术社区  · 11 年前

    我需要用C#将米转换成十进制度数。我继续阅读 Wikipedia 小数点后1度等于111.32公里。但它在赤道上,所以如果我位于赤道上方/下方,我的转换会出错吗? 我认为这是错误的:

    long sRad = (long.Parse(sRadTBx.Text)) / (111.32*1000); 
    

    编辑: 我需要这个搜索半径来查找附近的用户

        long myLatitude = 100;
        long myLongitude = 100;
        long sRad = /* right formula to convert meters to decimal degrees*/
    
    long begLat = myLatitude - searchRad;
    long endLat = myLatitude + searchRad;
    long begLong = myLongitude - searchRad;
    long endLong = myLongitude + searchRad;
    
    List<User> FoundUsers = new List<User>();
    
    foreach (User user in db.Users)
    {
        // Check if the user in the database is within range
        if (user.usrLat >= begLat && user.usrLat <= endLat && user.usrLong >= begLong && user.usrLong <= endLong)
        {
            // Add the user to the FoundUsers list
            FoundUsers.Add(user);
        }
    }
    
    2 回复  |  直到 11 年前
        1
  •  16
  •   Christofer Ohlsson    11 年前

    同样来自维基百科的那篇文章:

     As one moves away from the equator towards a pole, however,
     one degree of longitude is multiplied by
     the cosine of the latitude,
     decreasing the distance, approaching zero at the pole.
    

    这是纬度的函数:

    double GetSRad(double latitude)
    {
        return 111.32 * Math.Cos(latitude * (Math.PI / 180));
    }
    

    或类似。

    编辑:所以,如果要反过来,将米转换为十进制度数,您需要这样做:

    double MetersToDecimalDegrees(double meters, double latitude)
    {
        return meters / (111.32 * 1000 * Math.Cos(latitude * (Math.PI / 180)));
    }
    
        2
  •  8
  •   Matthew Haugen    11 年前

    克里斯托弗·奥尔森(Christopher Olsson)已经有了一个很好的答案,但我想我也会补充一些理论。

    我总是发现 this webpage 对这些公式有用。

    关于概念的简要说明

    想想实际的几何结构。

    目前,您所做的只是缩放输入。想象一下气球的经典例子。在气球上画两条在底部和顶部相交的线。这些表示经度线,因为它们是“上下”的 真正地 这样的概念,但我们可以想象。现在,如果你看每一条线,你会发现它们的长度随着你上下移动而变化。根据最初的规范,它们在气球的顶部和底部相遇,但在其他地方都不会相遇。经度线也是如此。非核素几何告诉我们,如果直线相交,那么它们正好相交两次,这很难概念化。但正因为如此,我们之间的距离在赤道上得到了有效的反映。

    正如你所看到的,纬度极大地影响了你的纵向线之间的距离。它们从北极和南极最接近的地方到赤道最远的地方都有不同。

    纬度线稍微容易一点。它们不收敛。如果你拿着我们的理论气球上下笔直,两极上下笔直——也就是说,纬度线将与地面平行。在更广义的意义上,它们将垂直于由纵向线的极点构成的轴(欧几里德概念)。因此,纬度之间的距离是恒定的,与经度无关。

    您的实施

    现在,您的实现依赖于这样的想法,即这些线始终保持恒定的距离。如果是这样的话,您就可以采取一种简单的缩放方法。如果它们实际上是欧几里得意义上的平行,那么它与从每小时英里转换为每小时公里的概念不会有太大不同。然而,距离的变化使这变得更加复杂。

    北极经度之间的距离为零,而在赤道,正如你引用的维基百科页面所说的那样,是111.32公里。因此,为了得到一个真正准确的结果,你必须考虑你所寻找的纬度。这就是为什么这变得更加复杂的原因。

    获得实际结果

    现在,你想要的公式,考虑到你最近的编辑,似乎你想把这两个纬度都结合起来 您的评估中的经度。给定您的代码示例,您似乎希望找到两个坐标之间的距离,并且希望它在短距离内正常工作。因此,我将建议,正如我在本文开头向您指出的网站所建议的那样,采用哈弗辛公式。那个网站提供了很多关于它的好信息,但这就是公式本身。我直接从网站上复制它,符号和所有的东西,以确保我不会犯任何愚蠢的错误。因此,这当然是JavaScript,但基本上只需更改一些情况,它将在C#中运行。

    其中,是纬度,是经度,是方位(以弧度为单位,从北顺时针),是角距离(以弧度计)d/R;d是行驶距离,R是地球半径

    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;
    

    我认为这里唯一必须注意的是 R 如第一行所示,是地球的半径。正如评论所示,我们已经在以公里为单位进行工作,因此您可能需要或不需要为实现更改。幸运的是,通过在线搜索可以很容易地找到以你最喜欢的单位表示的地球(平均)半径。

    当然,您还需要注意 toRadians 只是输入乘以 Math.PI ,然后除以180。很简单。

    可供替代的

    这不是 真正地 看起来与您的情况相关,但我会将其包括在内。上述公式将给出准确的结果,但这将以速度为代价。显然,对于任何个人记录来说,这都是一笔很小的交易,但随着你的能力越来越强,这可能会成为一个问题。如果是这样的话,如果你在一个相当集中的地方工作,你可以研究我们星球的巨大性质,找到适合一个纬度和经度之间的距离的数字,然后将这个星球视为“或多或少的欧几里得”(即平的),并使用毕达哥拉斯定理来计算这些值。当然,距离原始测试站点越远,这将变得越来越不准确(我个人会通过询问Google Earth或类似产品来找到这些数字)。但如果你面对的是密集的用户群, 方法 比运行一系列公式更快 Math 要锻炼的班级。

    另一个更抽象的选择

    你可能还想知道你在哪里做这个逻辑。在这里,我开始超出了我的能力范围,但如果您碰巧将数据存储在SQL Server中,它已经内置了一些非常酷的地理功能,可以为您处理距离计算。只需查看 GEOGRAPHY 类型

    编辑

    这是对一条评论的回应,表明期望的结果实际上是一个表示边界的矩形。现在,我建议不要这样做,因为它并不像你的代码所建议的那样是一个搜索“半径”。

    但如果你真的想坚持这种方法,你会看到两个不同的距离:一个是纬度,一个是经度。这也是来自该网页。 φ1 myLatitude λ1 myLongitude 。此公式接受方位和起始坐标,然后给出结果位置。

    var φ2 = Math.asin( Math.sin(φ1)*Math.cos(d/R) + Math.cos(φ1)*Math.sin(d/R)*Math.cos(brng) );
    var λ2 = λ1 + Math.atan2(Math.sin(brng)*Math.sin(d/R)*Math.cos(φ1), Math.cos(d/R)-Math.sin(φ1)*Math.sin(φ2));
    

    您可以使用它来确定搜索矩形的边界。