How to draw poly line with arrow head(It indicates the direction) using Android Maps V2 API. In Android Maps Documentation this option is not available.Is it possible to add arrows on polyline?
-
Is it possible to add arrows heads on polyline using Android maps v2. How to do this? any link? – Ramprasad Mar 26 '13 at 07:03
-
you mean to track down the route right!!! – Janmejoy Mar 26 '13 at 07:05
-
yes.I have multiple locations and I want to connect these locations and display as route using poly line with arrows. – Ramprasad Mar 26 '13 at 07:07
-
Is it possible to add arrow on poly line using Android maps v2 API? – Ramprasad Apr 01 '13 at 06:48
3 Answers
Here's a working example I've developed using the same concept as what Doug suggested, by taking a JavaScript example (http://econym.org.uk/gmap/example_arrows.htm) and converting it to Java code. For handiness it uses images from Google Maps servers, but these could images of your design or could be scraped off the web and stored locally in the app. I'm downloading these on main thread for sake of demonstration, but don't do that if using in a live app!!
The key difference to the JavaScript example though is that you have to project the arrow head image onto a larger image four times the size, working out where to translate the image to based on the bearing from A to B, and finally center that image over the existing B marker by adding another anchored marker with your larger image for an icon.
Firstly add your polylines:
PolylineOptions polylines = new PolylineOptions();
LatLng from = new LatLng(f.getLatitude(), f.getLongitude());
LatLng to = new LatLng(t.getLatitude(), t.getLongitude());
polylines.add(from, to).color(polyColor).width(2);
mMap.addPolyline(polylines);
DrawArrowHead(mMap, from, to);
Then add your arrow heads:
private final double degreesPerRadian = 180.0 / Math.PI;
private void DrawArrowHead(GoogleMap mMap, LatLng from, LatLng to){
// obtain the bearing between the last two points
double bearing = GetBearing(from, to);
// round it to a multiple of 3 and cast out 120s
double adjBearing = Math.round(bearing / 3) * 3;
while (adjBearing >= 120) {
adjBearing -= 120;
}
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
// Get the corresponding triangle marker from Google
URL url;
Bitmap image = null;
try {
url = new URL("http://www.google.com/intl/en_ALL/mapfiles/dir_" + String.valueOf((int)adjBearing) + ".png");
try {
image = BitmapFactory.decodeStream(url.openConnection().getInputStream());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (image != null){
// Anchor is ratio in range [0..1] so value of 0.5 on x and y will center the marker image on the lat/long
float anchorX = 0.5f;
float anchorY = 0.5f;
int offsetX = 0;
int offsetY = 0;
// images are 24px x 24px
// so transformed image will be 48px x 48px
//315 range -- 22.5 either side of 315
if (bearing >= 292.5 && bearing < 335.5){
offsetX = 24;
offsetY = 24;
}
//270 range
else if (bearing >= 247.5 && bearing < 292.5){
offsetX = 24;
offsetY = 12;
}
//225 range
else if (bearing >= 202.5 && bearing < 247.5){
offsetX = 24;
offsetY = 0;
}
//180 range
else if (bearing >= 157.5 && bearing < 202.5){
offsetX = 12;
offsetY = 0;
}
//135 range
else if (bearing >= 112.5 && bearing < 157.5){
offsetX = 0;
offsetY = 0;
}
//90 range
else if (bearing >= 67.5 && bearing < 112.5){
offsetX = 0;
offsetY = 12;
}
//45 range
else if (bearing >= 22.5 && bearing < 67.5){
offsetX = 0;
offsetY = 24;
}
//0 range - 335.5 - 22.5
else {
offsetX = 12;
offsetY = 24;
}
Bitmap wideBmp;
Canvas wideBmpCanvas;
Rect src, dest;
// Create larger bitmap 4 times the size of arrow head image
wideBmp = Bitmap.createBitmap(image.getWidth() * 2, image.getHeight() * 2, image.getConfig());
wideBmpCanvas = new Canvas(wideBmp);
src = new Rect(0, 0, image.getWidth(), image.getHeight());
dest = new Rect(src);
dest.offset(offsetX, offsetY);
wideBmpCanvas.drawBitmap(image, src, dest, null);
mMap.addMarker(new MarkerOptions()
.position(to)
.icon(BitmapDescriptorFactory.fromBitmap(wideBmp))
.anchor(anchorX, anchorY));
}
}
private double GetBearing(LatLng from, LatLng to){
double lat1 = from.latitude * Math.PI / 180.0;
double lon1 = from.longitude * Math.PI / 180.0;
double lat2 = to.latitude * Math.PI / 180.0;
double lon2 = to.longitude * Math.PI / 180.0;
// Compute the angle.
double angle = - Math.atan2( Math.sin( lon1 - lon2 ) * Math.cos( lat2 ), Math.cos( lat1 ) * Math.sin( lat2 ) - Math.sin( lat1 ) * Math.cos( lat2 ) * Math.cos( lon1 - lon2 ) );
if (angle < 0.0)
angle += Math.PI * 2.0;
// And convert result to degrees.
angle = angle * degreesPerRadian;
return angle;
}

- 3,007
- 2
- 31
- 30
-
If you did have the images downloaded and in your app, you could do something like this instead: `int identifier = getResources().getIdentifier("dir_" + String.valueOf((int)adjBearing), "drawable", getActivity().getPackageName()); Bitmap image = BitmapFactory.decodeResource(getResources(), identifier);` – Breeno Aug 15 '13 at 12:04
-
Also, if you were to scrape the images off the net and put them in your drawable folder, make sure to put them in a `drawable-nodpi` folder so they don't get scaled up for the screen density! – Breeno Aug 15 '13 at 12:24
-
1Andddd... disable map gesture rotation, as the arrows won't rotate with the map! `Map.getUiSettings().setRotateGesturesEnabled(false);` – Breeno Aug 15 '13 at 12:37
-
1I felt obligated to put -1, because there is no excuse for doing a network request on main thread. Also the input stream is not closed. – Display Name Jun 17 '15 at 08:22
As of Feb. 15, 2017 release of Android Maps API v2 you can now add custom Line caps to the end of polylines on Android Maps API v2, which can be arrows.
From the Line caps documentation:
The following snippet specifies a custom bitmap for the end cap:
mPolyline.setEndCap( new CustomCap(BitmapDescriptorFactory.fromResource(R.drawable.arrow), 16));
When you use a custom bitmap, you should specify a reference stroke width in pixels. The API scales the bitmap accordingly. The reference stroke width is the stroke width that you used when designing the bitmap image for the cap, at the original dimension of the image. The default reference stroke width is 10 pixels. Hint: To determine the reference stroke width, open your bitmap image at 100% zoom in an image editor, and plot the desired width of the line stroke relative to the image.
If you use
BitmapDescriptorFactory.fromResource()
to create the bitmap, make sure you use a density-independent resource (nodpi).
The post from Google for the related resolved issue here says:
We have added the ability to customize the start and end caps of Polylines with a custom bitmap. Using this you will be able to add arrowheads to your Polylines.
See information about Line Caps in the Shapes Guide here: https://developers.google.com/maps/documentation/android-api/shapes#line_caps
See an example in the new Polylines and Polygons tutorial here: https://developers.google.com/maps/documentation/android-api/polygon-tutorial#add_custom_styling_to_your_polyline
See the release notes here: https://developers.google.com/maps/documentation/android-api/releases#february_15_2017
See the blog post here: https://maps-apis.googleblog.com/2017/02/styling-and-custom-data-for-polylines.html

- 11,496
- 8
- 58
- 111
-
Hi Can you give an exampe of arrow image I'm interested in direction of it N, S, W or E e.g? – Vlad Dec 10 '18 at 15:34
I've not tried this but I think that it should be possible by using markers. You will need to create a series of, say 20, small arrows each pointing in different directions, 18, 36, 54 degrees etc. Then either when constructing the polyline or, probably better, as a separate process after the polyline has been built, run through all of the coordinates at whatever spacing you want and, at each chosen point get the bearing using locationn.getbearing and, from that bearing, determine which directional arrow to use as a marker and lay the appropriate marker at that point

- 437
- 1
- 5
- 17