Android - Draw a path (array of points) in MapView

Although this post differs from my blog routine I am writing because I haven’t found an efficient way of displaying a list of GeoPoints to a MapView. This is often useful when you want to display directions from Google service inside your Android application.

Key features:

  • A custom overlay that extends com.google.android.maps.Overlay
  • Efficient way of displaying a path. The path is drawn over the same overlay.
  • Smooth Lines, useful when there are a lot of corners like the example below
  • Easy to use
  • Easy to extend  - Just under 90 lines of code
  • Available on Bitbucket

Here is a sample result of using my overlay to display a list of points (The green marker is not included).

device-2012-01-02-150402

You can use it like this

List<GeoPoint> path = new ArrayList<GeoPoint>();
//add your points somehow...
mapView.getOverlays().add(new RoutePathOverlay(path));

Here is the complete RoutePathOverlay.java (it's also available on Bitbucket)

import java.util.List;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.RectF;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.Projection;

public class RoutePathOverlay extends Overlay {

        private int _pathColor;
        private final List<GeoPoint> _points;
        private boolean _drawStartEnd;

        public RoutePathOverlay(List<GeoPoint> points) {
                this(points, Color.RED, true);
        }

        public RoutePathOverlay(List<GeoPoint> points, int pathColor, boolean drawStartEnd) {
                _points = points;
                _pathColor = pathColor;
                _drawStartEnd = drawStartEnd;
        }

        private void drawOval(Canvas canvas, Paint paint, Point point) {
                Paint ovalPaint = new Paint(paint);
                ovalPaint.setStyle(Paint.Style.FILL_AND_STROKE);
                ovalPaint.setStrokeWidth(2);
                int _radius = 6;
                RectF oval = new RectF(point.x - _radius, point.y - _radius, point.x + _radius, point.y + _radius);
                canvas.drawOval(oval, ovalPaint);               
        }

        public boolean draw(Canvas canvas, MapView mapView, boolean shadow, long when) {
                Projection projection = mapView.getProjection();
                if (shadow == false && _points != null) {
                        Point startPoint = null, endPoint = null;
                        Path path = new Path();
                        //We are creating the path
                        for (int i = 0; i < _points.size(); i++) {
                                GeoPoint gPointA = _points.get(i);
                                Point pointA = new Point();
                                projection.toPixels(gPointA, pointA);
                                if (i == 0) { //This is the start point
                                        startPoint = pointA;
                                        path.moveTo(pointA.x, pointA.y);
                                } else {
                                        if (i == _points.size() - 1)//This is the end point
                                                endPoint = pointA;
                                        path.lineTo(pointA.x, pointA.y);
                                }
                        }

                        Paint paint = new Paint();
                        paint.setAntiAlias(true);
                        paint.setColor(_pathColor);
                        paint.setStyle(Paint.Style.STROKE);
                        paint.setStrokeWidth(5);
                        paint.setAlpha(90);
                        if (getDrawStartEnd()) {
                                if (startPoint != null) {
                                        drawOval(canvas, paint, startPoint);
                                }
                                if (endPoint != null) {
                                        drawOval(canvas, paint, endPoint);
                                }
                        }
                        if (!path.isEmpty())
                                canvas.drawPath(path, paint);
                }
                return super.draw(canvas, mapView, shadow, when);
        }

        public boolean getDrawStartEnd() {
                return _drawStartEnd;
        }

        public void setDrawStartEnd(boolean markStartEnd) {
                _drawStartEnd = markStartEnd;
        }
}

I hope you find it useful!Cheers!

15 Comments

  • 




Roberto

    So good...it works! Many thanks

  • 




Ajay

    Its Awesome... Keep it Up.. Good Work..

  • 




Stuart

    Thanks so much!
    $1Easy to set up and use- couldn't be any simpler!

  • 




Kiran

    Nice example but i am unable to draw lines can u please share me complete code
    $1Actually my requirement is asked in the below link.
    $1
    $1http://stackoverflow.com/questions/10546150/how-to-measure-area-from-current-location-to-another-location-using-gps-coordina
    $1
    $1can u please give me any idea on this.

  • Ralph Metel on said

    Reply
    




Ralph Metel

    It works perfectly, ty very much!!! ;)

  • 




Eduardo

    Really inefficient. The loop can be done as something like
    $1
    $1for (int i = 1; i < _points.size(); i++) {
    $1 projection.topixels(_points.get(i), pointa);
    $1 projection.topixels(_points.get(i-1), pointb);
    $1 // changing here accordingly
    $1}
    $1
    $1and then out of the loop you do the stuff, e.g.,
    $1moveto(_points.get(0)) // move to the starting point.
    $1
    $1it is way better than using a mangled loop with if i == 0 that is going to be true only once inside the loop, and also checking if (i == _points.size() - 1) requiring to calculate the size of the points array on every iteration of the loop. really inefficient!
    $1
    $1 _points.size();="" i++)="" {="" projection.topixels(_points.get(i),="" pointa);="" projection.topixels(_points.get(i-1),="" pointb);="" changing="" here="" accordingly="" }="" and="" then="" out="" of="" the="" loop="" you="" do="" the="" stuff,="" e.g.,="" moveto(_points.get(0))="" move="" to="" the="" starting="" point.="" it="" is="" way="" better="" than="" using="" a="" mangled="" loop="" with="" if="" i="=" 0="" that="" is="" going="" to="" be="" true="" only="" once="" inside="" the="" loop,="" and="" also="" checking="" if="" (i="=" _points.size()="" -="" 1)="" requiring="" to="" calculate="" the="" size="" of="" the="" points="" array="" on="" every="" iteration="" of="" the="" loop.="" really="" inefficient!=""></ _points.size(); i++) {
    $1 projection.topixels(_points.get(i), pointa);
    $1 projection.topixels(_points.get(i-1), pointb);
    $1 // changing here accordingly
    $1}
    $1
    $1and then out of the loop you do the stuff, e.g.,
    $1moveto(_points.get(0)) // move to the starting point.
    $1
    $1it is way better than using a mangled loop with if i == 0 that is going to be true only once inside the loop, and also checking if (i == _points.size() - 1) requiring to calculate the size of the points array on every iteration of the loop. really inefficient!
    $1
    $1>

  • Gregg Reno on said

    Reply
    




Gregg Reno

    John - this works great! One question though - why is it when I zoom in, at some point the routes are no longer displayed?
    $1
    $1I have a few points in a city that are a few blocks from each other. Zoomed out, the route is fine, but zooming in to see, say two blocks at a time, it's no longer visible.
    $1
    $1Thanks again for the great example.
    $1-Gregg

  • 




venkat

    hi,
    $1 i want route map between current location and already fixed location.
    $1Here source address is take as current location and destination is already fixed in program.please give me example code for this one....iam irretating so many days for this problem.
    $1 Thanks.

  • 




Alex

    Apla Euxaristw..!
    $1Thanks..!

  • 




Vijay

    Perfect example i am looking for
    $1
    $1Thanks

  • 




pawel

    Is it possible to get real path (i mean path which coming through roads), not just straight line between geopoints?

  • 




Neeraj

    Not use full example create only line to start and destination place not create real route.

  • 




sweety

    This code will not work for curved path. it is only for straight line.
    $1Hi Bloger, can you please tell me how can l show the driving path in the map.
    $1
    $1Thanks in advane....

  • 




Santosh

    Thanks a lot... You code done lots of things to me... Once Again Thank You Very Much.... Keep it up.

  • 




Santosh

    Hi,
    $1
    $1I am trying to pass multiple (different) Group of array of GeoPoints in loop. (means Route1, Route2) but In My output i am Getting route only for Route2 map) These route1 and route2 contains a set of GeoPoints.
    $1
    $1I called RoutePathOverlay class two times in loop. Map Showing for only second call of GeoPoints.

Add a Comment (gravatar-enabled)