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).
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!
Roberto on said
So good...it works! Many thanks
Ajay on said
Its Awesome... Keep it Up.. Good Work..
Stuart on said
Thanks so much!
$1Easy to set up and use- couldn't be any simpler!
Kiran on said
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
It works perfectly, ty very much!!! ;)
Eduardo on said
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
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 on said
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 on said
Apla Euxaristw..!
$1Thanks..!
Vijay on said
Perfect example i am looking for
$1
$1Thanks
pawel on said
Is it possible to get real path (i mean path which coming through roads), not just straight line between geopoints?
Neeraj on said
Not use full example create only line to start and destination place not create real route.
sweety on said
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 on said
Thanks a lot... You code done lots of things to me... Once Again Thank You Very Much.... Keep it up.
Santosh on said
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.