【问题标题】:Calculating points on a circle that is projected onto the Earth计算投影到地球上的圆上的点
【发布时间】:2017-03-08 02:12:07
【问题描述】:

我正在使用 osgEarth,我正在尝试绘制从一个点突出到一个圆的线。 起初,我尝试执行以下操作(其中 m_x_start_lon 和 m_y_start_lat 是一些任意起点):

    double x_lon = 0.0f;
    double y_lat = 0.0f;
    if (!GetPointFromScreen(args, x_lon, y_lat)) return true;

    m_stop_x_lon = x_lon;
    m_stop_y_lat = y_lat;

    double x_dist = abs(m_stop_x_lon - m_start_x_lon);
    double y_dist = abs(m_stop_y_lat - m_start_y_lat);

        m_radius = sqrtf(x_dist * x_dist + y_dist * y_dist);

    std::vector<double> x_points(m_slices);
    std::vector<double> y_points(m_slices);

    //m_slices = 30, which is the number of lines to represent the circle
    for (std::size_t i = 0u; i < m_slices; ++i)
    {
        double new_x = m_start_x_lon + m_radius * cos(i);
        double new_y = m_start_y_lat + m_radius * sin(i);

        x_points.at(i) = new_x;
        y_points.at(i) = new_y;
    }

但是,这只是一种工作。我能得出的唯一结论是,使用纬度和经度会以某种方式扭曲结果。

半径水平约 190 米,垂直约 340 米。我知道当你远离两极时会发生挤压,但我认为直到它超过至少几公里的长度后才会如此极端。即使这样,水平和垂直半径也应该匹配。

那么,我必须怎么做才能为我的圆的边缘获得正确的经纬度坐标?

【问题讨论】:

  • 我没有时间写一个有用的答案,但你必须考虑到,对于一个半径超过几公里的圆,在热带以外的任何一点,它 倾斜,因为纵向线在两极处相交。如果要避免挤压,您需要在计算圆之前将圆投影到椭球体上,或者将坐标系从正在使用的大地水准面投影回 3D 空间。
  • 哦,我知道挤压问题。它咬了我好几次。但是,我认为这不是问题。我应该将距离添加到我的原始帖子中,但水平半径约为 190 米,垂直半径约为 340 米(当它们应该相同时)。我不认为挤压会如此极端

标签: c++ geometry geospatial geo


【解决方案1】:

这段 javascript 代码(对不起,没有 C++)选择一个随机方位,并在该方向上与给定起点的特定距离处绘制一个点。

function pointAtDistance(inputCoords, distance) {
    const result = {}
    const coords = toRadians(inputCoords)
    const sinLat =  Math.sin(coords.latitude)
    const cosLat =  Math.cos(coords.latitude)

    const bearing = Math.random() * TWO_PI
    const theta = distance/EARTH_RADIUS
    const sinBearing = Math.sin(bearing)
    const cosBearing =  Math.cos(bearing)
    const sinTheta = Math.sin(theta)
    const cosTheta =    Math.cos(theta)

    result.latitude = Math.asin(sinLat*cosTheta+cosLat*sinTheta*cosBearing);
    result.longitude = coords.longitude + 
    Math.atan2( sinBearing*sinTheta*cosLat, cosTheta-sinLat*Math.sin(result.latitude )
        );
    result.longitude = ((result.longitude+THREE_PI)%TWO_PI)-Math.PI

    return toDegrees(result)
}

inputCoords 是一个 {latitude: n, longitude: m} 的对象

Please see the jsFiddle here 在这里您可以找到丢失的位,例如常量值和实用程序函数。

EARTH_RADIUS 以米为单位,因此您以米为单位指定距离

结果经度被限制在 -180 -> +180 度范围内

如果你想让点规则地分布在圆周围,撕掉随机轴承部分并传入 0 到 TWO_PI 之间的数字

编辑:我应该提一下,这段代码是基于this page的算法

【讨论】:

    【解决方案2】:

    在计算 m_slices 循环时,不是将角度切片为 (2 * PI / m_slices),而是在计算 sin()cos () 的 i 是从 0 到 m_slices。

    double dAngle = (2 * PI / m_slices); // in radian
    
    for (std::size_t i = 0u; i < m_slices; ++i)
    {
        double new_x = m_start_x_lon + m_radius * cos(i * dAngle);
        double new_y = m_start_y_lat + m_radius * sin(i * dAngle);
    
        x_points.at(i) = new_x;
        y_points.at(i) = new_y;
    }
    

    【讨论】:

      【解决方案3】:

      好吧,我想通了——我(愚蠢地)认为用 lat,lon 计算的半径是一致的。 为了解决这个问题,我改为获取从开始到停止的距离(以米为单位),并将其用作我的半径来找到正确的纬度、经度点。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-04-23
        • 1970-01-01
        • 2012-02-12
        • 2017-07-30
        • 2020-01-27
        相关资源
        最近更新 更多