Draw ARC Polyline in Google Map
Asked Answered
T

4

12

How Can I Draw Arc Polyline in Google Map ?

I already used this code to create curved Polyline.

Here is the method to draw curved Polyline:

private void showCurvedPolyline (LatLng p1, LatLng p2, double k) {
    //Calculate distance and heading between two points
    double d = SphericalUtil.computeDistanceBetween(p1,p2);
    double h = SphericalUtil.computeHeading(p1, p2);

    //Midpoint position
    LatLng p = SphericalUtil.computeOffset(p1, d*0.5, h);

    //Apply some mathematics to calculate position of the circle center
    double x = (1-k*k)*d*0.5/(2*k);
    double r = (1+k*k)*d*0.5/(2*k);

    LatLng c = SphericalUtil.computeOffset(p, x, h + 90.0);

    //Polyline options
    PolylineOptions options = new PolylineOptions();
    List<PatternItem> pattern = Arrays.<PatternItem>asList(new Dash(30), new Gap(20));

    //Calculate heading between circle center and two points
    double h1 = SphericalUtil.computeHeading(c, p1);
    double h2 = SphericalUtil.computeHeading(c, p2);

    //Calculate positions of points on circle border and add them to polyline options
    int numpoints = 100;
    double step = (h2 -h1) / numpoints;

    for (int i=0; i < numpoints; i++) {
        LatLng pi = SphericalUtil.computeOffset(c, r, h1 + i * step);
        options.add(pi);
    }

    //Draw polyline
    mMap.addPolyline(options.width(10).color(Color.MAGENTA).geodesic(false).pattern(pattern));
}

OUTPUT

1. If I am using this.showCurvedPolyline(latLng1, latLng2, 0.1); then getting:

enter image description here

As you can see in above image, we are very close to get our target, but don't know why it's not connecting with another end point

2. If I am using this.showCurvedPolyline(latLng1, latLng2, 1); then getting:

enter image description here

3. If I am using LatLng c = SphericalUtil.computeOffset(p, x, h - 90.0); then getting:

enter image description here

Note: I don't want this much big circle shape, really I don't want that much height.

Here is what I want an ARC Shape as shown in below image

enter image description here

Here is the CODE I am using to add curved Polyline between two geo-locatios :

private void addCurvedPolyLine() {

        LatLng latLng1 = new LatLng(40.7128, 74.0059); // New York
        LatLng latLng2 = new LatLng(51.5074, 0.1278); // London

        Marker marker1 = mMap.addMarker(new MarkerOptions().position(latLng1).title("Start"));
        Marker marker2 = mMap.addMarker(new MarkerOptions().position(latLng2).title("End"));

        LatLngBounds.Builder builder = new LatLngBounds.Builder();

        builder.include(marker1.getPosition());
        builder.include(marker2.getPosition());

        LatLngBounds bounds = builder.build();
        int padding = 0; // offset from edges of the map in pixels
        CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, padding);
        mMap.moveCamera(cu);
        mMap.animateCamera(cu);

        this.showCurvedPolyline(latLng1, latLng2, 0.1);

    }
Ton answered 25/9, 2017 at 17:51 Comment(6)
He has provided a solution by using k=1 instead of k==1, see his second problem in quick fix here.Gropius
@LalitSinghFauzdar I didn't find k==1 anywhere in above method, can you tell me exactly where I need to make changes.Ton
see this function call this.showCurvedPolyline(sydney1,sydney2, 0.5); 0.5 here is the value of k, try passing 1 here.Gropius
Sorry I forgot to tell you I already tried with 1.0 and 1 but same problem: this.showCurvedPolyline(latLng2, latLng1, 1);Ton
As they have mentioned "The last parameter k defines the curvature of the polyline, it can be >0 and <=1. In my example I used k=0.5", Have you tried changing that value to .2 or .3 which is less than the previous value. Also, changing 0.5 to 1 led to any change?Gropius
@LalitSinghFauzdar Please have a look above, I just updated few things.Ton
P
8

The solution that I proposed in another question was focused on curved polylines for really small distances. For example, when you have a Directions API route where the start and end points are snapped to road, but the real start and end points in original request were the positions of buildings, so you can connect the road and building with this curved dashed polyline.

In case of big distances like in your example, I believe you can just use a geodesic polylines that are available in the API. You can set geodesic property of polyline options to true.

public void onMapReady(GoogleMap googleMap) {
    mMap = googleMap;

    mMap.getUiSettings().setZoomControlsEnabled(true);

    LatLng latLng1 = new LatLng(40.7128, 74.0059); // New York
    LatLng latLng2 = new LatLng(51.5074, 0.1278); // London

    Marker marker1 = mMap.addMarker(new MarkerOptions().position(latLng1).title("Start"));
    Marker marker2 = mMap.addMarker(new MarkerOptions().position(latLng2).title("End"));

    List<PatternItem> pattern = Arrays.<PatternItem>asList(new Dash(30), new Gap(20));
    PolylineOptions popt = new PolylineOptions().add(latLng1).add(latLng2)
       .width(10).color(Color.MAGENTA).pattern(pattern)
       .geodesic(true);
    mMap.addPolyline(popt);

    LatLngBounds.Builder builder = new LatLngBounds.Builder();

    builder.include(marker1.getPosition());
    builder.include(marker2.getPosition());

    LatLngBounds bounds = builder.build();
    int padding = 150; // offset from edges of the map in pixels
    CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, padding);
    mMap.moveCamera(cu);
    mMap.animateCamera(cu);
}  

The resulting polyline is shown in my screenshot

enter image description here

I hope this helps!

Politico answered 4/10, 2017 at 15:18 Comment(1)
Hey, I did the same thing you said, but it's not helping, it's still showing a straight line.Casease
Q
3

Here is Route object I am using after some improvement from @xomena

Route.java

My changes:

  • Use heading - 90.0 instead of heading + 90.0
  • Rename variables, make constants (Still figuring out what is some part of the code is doing...)
  • Rewrite with my new logic

Basically, I only draw a curve route if the distance between origin and dest is less than 1000km. For longer distance, as I mentioned in here, I found out the part h1 + i * step inside the loop make a small error due to double calculation error in every iterator and make the final route not being placed correctly.

My safe choice is to draw a crow flight route instead, but my suggestion is not to use k = 1 for this, it's not performance efficiency. I wrote another method which just adds origin and dest points to the Route, skips all other complex calculation.

I will try to come back with this long-curve route problem in the future, for now, this solution still suitable for my problem.

EDIT:

Here is my solution for the second problem so far:

  • Change heading + 90 or heading - 90 didn't fix the problem, so don't
  • Instead, change the step variable calculation like this:

    double step = Math.toDegrees(Math.atan(distance / 2 / midPerpendicularLength)) * 2 / DEFAULT_CURVE_POINTS;

Quintus answered 26/9, 2017 at 4:26 Comment(7)
Thanks for sharing this, can you share code of an Activity class and things we need to add in our build.gradle as I am getting: cannot resolve symbol 'DirectionApiResponse'... If possible so please upload a demo source code on Github as @Politico did for us... therefore today we are able to make discussions on it and you the second one who is helping in continuing this discussion - Thanks a lot.Ton
actually I would like to answer this question to earn 100 bounty points :) #46104180 (Therefore I am using New York and London as two Geo-Locations) and I want to achieve same thing I achieved already but with Arc shapeTon
I just used -90 and uploaded screenshot above, please check yet not resolvedTon
You can ignore the DirectionApiResponse part and remove it. Are you sure that you only change -90 and nothing else because it looks weird?Quintus
Yes you can try at your end, I just want to get with these GeoLocations: LatLng latLng1 = new LatLng(40.7128, 74.0059); // New York LatLng latLng2 = new LatLng(51.5074, 0.1278); // London Please share your updated code for the same.... As you know I tried my best...Ton
Actually, this is a company's project and my Route.java above is all I did for this logic. For us, it's not a critical feature and I am currently busy with other tasks so I will come back to fix this laterQuintus
Actually now I want to complete this one ASAP, as I already done 90% of task, so now this is for me craze to done this.... therefore I started bountyTon
L
2

Hy , you need to change your showCurvePolyline method with this method.

    private void showCurvedPolyline (LatLng p1, LatLng p2, double k) {
    //Calculate distance and heading between two points
    double d = 0;


if (d == 0)
        d= SphericalUtil.computeDistanceBetween(origin, dest);



double h = SphericalUtil.computeHeading(p1, p2);

    // Calculate midpoint position
    LatLng midPoint = SphericalUtil.computeOffset(p1, d / 2, h);




    //Apply some mathematics to calculate position of the circle center
    double x = (1-k*k)*d*0.5/(2*k);
    double r = (1+k*k)*d*0.5/(2*k);

    LatLng c = SphericalUtil.computeOffset(p, x, h + 90.0);

    //Polyline options
    PolylineOptions options = new PolylineOptions();
    List<PatternItem> pattern = Arrays.<PatternItem>asList(new Dash(30), new Gap(20));

    //Calculate heading between circle center and two points
    double h1 = SphericalUtil.computeHeading(c, p1);
    double h2 = SphericalUtil.computeHeading(c, p2);

// Calculate position of the curve center point
    double sqrCurvature = DEFAULT_CURVE_ROUTE_CURVATURE * DEFAULT_CURVE_ROUTE_CURVATURE;
    double extraParam = distance / (4 * DEFAULT_CURVE_ROUTE_CURVATURE);
    double midPerpendicularLength = (1 - sqrCurvature) * extraParam;
    double r = (1 + sqrCurvature) * extraParam;

    LatLng midCurvePoint = SphericalUtil.computeOffset(midPoint, midPerpendicularLength, heading - 90.0);

    // Calculate heading between circle center and two points
    double headingToOrigin = SphericalUtil.computeHeading(midCurvePoint, origin);
    double headingToDest = SphericalUtil.computeHeading(midCurvePoint, dest);
    // Calculate positions of points on the curve
    double step = (headingToDest - headingToOrigin) / DEFAULT_CURVE_POINTS;

    List<LatLng> points = new ArrayList<>();
    for (int i = 0; i < DEFAULT_CURVE_POINTS; ++i) {
        points.add(SphericalUtil.computeOffset(midCurvePoint, r, headingToOrigin + i * step));
    }


    for (int i=0; i <points; i++) {
        LatLng pi = SphericalUtil.computeOffset(c, r, h1 + i * step);
        options.add(pi);
    }

    //Draw polyline
    mMap.addPolyline(options.width(10).color(Color.MAGENTA).geodesic(false).pattern(pattern));
}

then you can draw the arcPolyLine.It was provided in the File Provided by previous answer.

Loot answered 2/10, 2017 at 11:8 Comment(2)
Hy Sonali have a look at this answer.Loot
There are a few undefined variables like DEFAULT_CURVE_ROUTE_CURVATURE in your code.Strife
P
2

There is another way to draw an arc. Using the google maps projection API to draw the polylines on an overlay view enables us to do a lot of things. Check this repo that has an example.

enter image description here

Poop answered 25/4, 2019 at 7:56 Comment(1)
How can we do this using Flutter? Someone know please let me know.Oas

© 2022 - 2024 — McMap. All rights reserved.