4

I want to draw a curve (Beizer curve) between two lat-long points. Currently i am referring this post (code is in javascript).

Code to get curve points using cubic bezier equation

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));
}

Following are the pictures show different test cases I tried.

case 1: P1 - Mumbai, P2 - Chennai case 1

case 2: P1 - France, P2 - Singapore case 2

case 3: P1 - USA, P2 - Bangalore case 3

case 4: P1 - USA, P2 - Singapore case 4

Questions:

1) Why is algorithm able to draw fairly decent curve only in case 1?

2) Why bezier curve bents on one side in case 2?

3) Why bezier curve looks different in case 3 and 4 (strange cusp at P1 (case 3) and at P2 (case 4)). Is there anyway to avoid it?

4) Why polyline is drawn differently (the direction?) in case 4?

I am unable to understand the pattern in which curve is drawn. Please let me know if I am doing anything wrong.

Sarweshkumar C R
  • 543
  • 1
  • 8
  • 19
  • @pskink Thanks, I will try it out. – Sarweshkumar C R Dec 23 '17 at 08:35
  • something to consider: why would those bent curves be wrong? Step 1 would be to get a *sphere* with the earth on it, and see if your curves are actually wrong, or whether you're simply looking at the effect of world map projections not being invariant to great circles on a globe. Grab google earth (the application), make it draw the great circles between your test points, and see if that goes through the same points your own curves go through. – Mike 'Pomax' Kamermans Dec 31 '17 at 11:30
  • Bless you God, man) you saved my life!) – Georgiy Chebotarev Apr 17 '19 at 19:22
  • @SarweshkumarCR how did you fix it? – shinzou Sep 06 '20 at 17:56
  • @shinzou Distortions are normal over a long distance with the above-mentioned approach (Hard to avoid at least). So, I came up with a different approach. I used screen pixel points to draw the curve rather than lat-long points. It worked well for me and I made an [Android library](https://github.com/sarweshkumar47/Curve-Fit) as well ([Curve-Fit](https://play.google.com/store/apps/details?id=com.makesense.labs.curvefitexample&hl=en_IN)). Kindly check it to know more about it. – Sarweshkumar C R Sep 08 '20 at 10:16
  • Nice, I'm having this problem when trying to draw a curve over a map in the browser, do you think I could use your logic? – shinzou Sep 08 '20 at 11:40
  • Hmm if I understood your solution correctly if the user will move the map or zoom in or out the curves will stay on top of it right? so this forces us to make the map unmoveable. – shinzou Sep 08 '20 at 11:43
  • @shinzou I think you can use the technique I mentioned to draw a curve in the browser. Whatever objects you draw on the map (curves, polylines, markers, polygons) will stay there until you clear them. – Sarweshkumar C R Sep 09 '20 at 04:48

1 Answers1

2

This answer is somewhat specative, but I suggest that nothing you are seeing is actually wrong or even unexpected. As you know, the Earth is round, but Google Maps (and computer screens) are inherently flat and two dimensional. The way we begin creating a flat 2D map of the Earth is by carving up a globe like this:

enter image description here

Things get somewhat warped and skewed in the process of creating the 2D map of the world to which we are all accustomed to see. I don't have the maths to back it up, but it seems obvious that 3D curves connecting two cities across most of the globe would also get warped and skewed after projecting them onto a 2D map. And I would expect the distortions to get more pronounced the longer the curves are.

This also would explain why the curve from Mumbai to Chennai looks normal to you. It is over a relatively short distance, where distortions due to the curvature of the Earth are minimal.

Tim Biegeleisen
  • 502,043
  • 27
  • 286
  • 360