在Google地图Android应用中,在两个经纬度点之间绘制一条曲线(贝塞尔曲线)。

4
我希望能在两个经纬度点之间绘制一条曲线(贝塞尔曲线)。目前我正在参考this post(该代码使用JavaScript编写)。 使用三次贝塞尔方程获取曲线点的代码
private void drawElementsOnMap(LatLng init, LatLng end) {

    mMap.addMarker(new MarkerOptions().position(init));
    mMap.addMarker(new MarkerOptions().position(end));

    LatLngBounds.Builder bc = new LatLngBounds.Builder();
    bc.include(init);
    bc.include(end);

    mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bc.build(), 100));

    PolylineOptions line = new PolylineOptions();
    line.add(init);
    line.add(end);
    mMap.addPolyline(line);

    double distanceBetween = SphericalUtil.computeDistanceBetween(init, end);
    double lineHeadingInit = SphericalUtil.computeHeading(init, end);  
    double lineHeadingEnd = bearing(end, init);*/

    double lineHeading1, lineHeading2;
    if (lineHeadingInit < 0) {
        lineHeading1 = lineHeadingInit + 45;
        lineHeading2 = lineHeadingInit + 135;
    } else {
        lineHeading1 = lineHeadingInit + -45;
        lineHeading2 = lineHeadingInit + -135;
    }

    LatLng pA = SphericalUtil.computeOffset(init, distanceBetween / 2.5, lineHeading1);
    LatLng pB = SphericalUtil.computeOffset(end, distanceBetween / 2.5, lineHeading2);

    // Beizer curves with 4 points
    gmapsCubicBezier(init, end, pA, pB);
}

private void gmapsCubicBezier(LatLng p1, LatLng p2, LatLng pA, LatLng pB) {

    //Polyline options
    PolylineOptions options = new PolylineOptions();

    LatLng curveLatLng = null;
    for (double t = 0.0; t < 1.01; t += 0.01) {
        // P = (1−t)3P1 + 3(1−t)2tP2 +3(1−t)t2P3 + t3P4; for 4 points
        double arcX = (1 - t) * (1 - t) * (1 - t) * p1.latitude
                + 3 * (1 - t) * (1 - t) * t * pA.latitude
                + 3 * (1 - t) * t * t * pB.latitude
                + t * t * t * p2.latitude;
        double arcY = (1 - t) * (1 - t) * (1 - t) * p1.longitude
                + 3 * (1 - t) * (1 - t) * t * pA.longitude
                + 3 * (1 - t) * t * t * pB.longitude
                + t * t * t * p2.longitude;

        curveLatLng = new LatLng(arcX, arcY);
        options.add(curveLatLng);
        //Draw polyline
        mMap.addPolyline(options.width(5).color(Color.DKGRAY).geodesic(false));
    }
    mMap.addMarker(new MarkerOptions().position(curveLatLng));
}

以下是展示我尝试的不同测试用例的图片。
案例1:P1-孟买,P2-钦奈 case 1 案例2:P1-法国,P2-新加坡 case 2 案例3:P1-美国,P2-班加罗尔 case 3 案例4:P1-美国,P2-新加坡 case 4 问题:

1) 为什么算法只能在情况1下绘制出相当不错的曲线?

2) 为什么贝塞尔曲线在情况2下会向一侧弯曲?

3) 为什么贝塞尔曲线在情况3和4中看起来不同(P1处有奇怪的尖点(情况3)和P2处有尖点(情况4))。有没有办法避免这种情况?

4) 为什么折线在情况4下绘制方式不同(方向?)?

我无法理解曲线绘制的模式。如果我做错了什么,请告诉我。


@pskink 谢谢,我会试试看。 - Sarweshkumar C R
需要考虑的一点是:为什么那些弯曲的曲线会是错误的?第一步是获取一个带有地球的球体,看看你的曲线是否真的错误,或者你只是在看到世界地图投影不具备对球体上的大圆不变性的影响。使用谷歌地球(应用程序),让它绘制测试点之间的大圆,并查看它是否穿过与你自己的曲线相同的点。 - Mike 'Pomax' Kamermans
谢谢你,上帝啊,你救了我的命! - Georgiy Chebotarev
@SarweshkumarCR 你是怎么解决的? - shinzou
@shinzou 上述方法在长距离上会出现扭曲是正常的(至少很难避免)。因此,我想出了一种不同的方法。我使用屏幕像素点来绘制曲线,而不是经纬度点。这对我很有效,我还制作了一个Android库Curve-Fit)。请查看以了解更多信息。 - Sarweshkumar C R
显示剩余3条评论
1个回答

2
这个答案有些推测性,但是我建议你所看到的一切都不是错的甚至是意料之中的。正如你所知,地球是圆的,但是谷歌地图(和计算机屏幕)本质上是平面和二维的。我们开始创建一个平面的二维地图是通过像这样切割地球:

enter image description here

在创建我们所熟悉的世界地图的过程中,事物会变得有些扭曲和偏斜。虽然我没有数学依据,但很明显,在将连接两个城市的三维曲线投影到二维地图上后,它们也会变形和扭曲。而且我认为,这种扭曲现象会随着曲线长度的增加而变得更加明显。

这也可以解释为什么从孟买到钦奈的曲线对你来说看起来很正常。这是因为它经过的距离相对较短,因此由于地球曲率引起的扭曲最小。


你认为在测地线坐标系中绘制贝塞尔曲线是否可能? - shinzou

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接