给定4个纬度/长度和轴承的边界框

时间:2013-10-18 17:07:13

标签: java android latitude-longitude bounding-box

我需要找到一个给定4个纬度/长点和一个方位的边界框(如示例图片所示)。我总是知道哪个两个点由轴承排列(示例中为1和2),因此我将始终知道边界框的长度。然而宽度是任意的,点是沿着线的任何位置(在示例中为3和4)。

enter image description here

我的第一个想法是,我必须计算点之间的角度(1& 3,1& 4,2& 3,2& 4),然后使用一系列&# 34;余弦定律"计算角点的方程式。有更简单的方法吗?这甚至会起作用吗?

1 个答案:

答案 0 :(得分:1)

所以环顾四周,甚至询问可能是一个更合适的网站(这里),我找到了一个基于Chris Veness(here)的东西的解决方案来找到给出两点及其方位的交点。因此,为了获得边界框的角落,我只需要采用顶部/底部和左/右(1& 3,1和4,2和3,2和4)的每个组合,并使用已知的方法找到交叉点。轴承和相应的调整。例如,为了找到图像的右下角,我将计算点1和1的交点。 3使用轴承+ 90表示点1的方向和轴承 - 180表示点3的方向。

我不能相信这个算法,甚至可以用几何方式来解释它,但它在我的测试中起作用。以下是我从Chris提供的javascript版本的java翻译

public static CoordD getIntersection(CoordD point1, double bearing1, CoordD point2, double bearning2) {
    double lat1 = rad(point1.latitude); double lon1 = rad(point1.longitude);
    double lat2 = rad(point2.latitude); double lon2 = rad(point2.longitude);
    double bearing13 = rad(bearing1); double bearing 23 = rad(bearing2);
    double dLat = lat2 - lat1; double dLon = lon2 - lon1;

    double dist12 = 2 * Math.asin( Math.sqrt( Math.sin(dLat / 2) * Math.sin(dLat / 2) +
        Math.cos(lat1) * Math.cos(lat2) * Math.sin(dLon / 2) * Math.sin(dLon / 2) ) );
    if (dist12 == 0) return null;

    double bearingA = Math.acos( ( Math.sin(lat2) - Math.sin(lat1) * Math.cos(dist12) ) /
        ( Math.sin(dist12) * Math.cos(lat1) ) );
    double bearingB = Math.acos( ( Math.sin(lat1) - Math.sin(lat2) * Math.cos(dist12) ) /
        ( Math.sin(dist12) * Math.cos(lat2) ) );
    if (Double.isNaN(bearingA)) bearingA = 0;
    if (Double.isNaN(bearingB)) bearingB = 0;

    double bearing12, bearing21;
    if (Math.sin(dLon) > 0) {
        bearing12 = bearingA;
        bearing21 = 2 * Math.PI - bearingB;
    } else { 
        bearing12 = 2 * Math.PI - bearingA;
        bearing21 = bearingB;
    }

    double alpha1 = (bearing13 - bearing12 + Math.PI) % (2 * Math.PI) - Math.PI; // Angle 2-1-3
    double alpha2 = (bearing21 - bearing23 + Math.PI) % (2 * Math.PI) - Math.PI; // Angle 1-2-3

    if (Math.sin(alpha1) == 0 && Math.sin(alpha2) == 0) return null; // Infinite intersections
    if (Math.sin(alpha1) * Math.sin(alpha2) < 0) return null; // Ambiguous intersection

    // needed?
    // alpha1 = Math.abs(alpha1);
    // alpha2 = Math.abs(alpha2);

    double alpha3 = Math.acos( -Math.cos(alpha1) * Math.cos(alpha2) +
        Math.sin(alpha1) * Math.sin(alpha2) * Math.cos(dist12) );
    double dist13 = Math.atan2( Math.sin(dist12) * Math.sin(alpha1) * Math.sin(alpha2),
        Math.cos(alpha2) + Math.cos(alpha1) * Math.cos(alpha3) );

    double lat3 = Math.asin( Math.sin(lat1) * Math.cos(dist13) +
        Math.cos(lat1) * Math.sin(dist13) * Math.cos(bearing13) );

    double dLon13 = Math.atan2( Math.sin(bearing13) * Math.sin(dist13) * Math.cos(lat1),
        Math.cos(dist13) - Math.sin(lat1) * Math.sin(lat3) );
    double lon3 = lon1 + dLon3;
    lon3 = (lon3 + 3 * Math.PI) % ( 2* Math.PI) - Math.PI // normalize to +/-180

    return new CoordD(deg(lat3), deg(lon3));
}

rad()deg()只是在弧度和度数之间转换的辅助函数。 CoordD是一个辅助类,它只包含两个用于存储纬度/经度的双点。