I draw routes on my google map using next code:
private void drawRoute(List<Route> route) {
for (int i = route.size() - 1; i >= 0 ; i--) {
final Route currentRoute = route.get(i);
final PolylineOptions polyOptions = new PolylineOptions();
polyOptions.color(Color.parseColor(allColors[inc_color]));
polyOptions.width(10);
polyOptions.addAll(currentRoute.getPoints());
mMap.addPolyline(polyOptions);
}
}
After this step I want to get from my SQLite database all PoI that are at max 5 km far from my routes and to draw them on map.
How can I filter my database as result to show all locations that are located at max 5 km along the route?
Maybe getting the bounds of route?
In Google Maps from browser which has the curved dashed line look like this:
But when I implement Google Maps in my own Android project, it didn't show this line
How can I draw this line?
You can implement the curved dashed polyline between two points. For this purpose you can use Google Maps Android API Utility Library that has SphericalUtil class and apply some math in your code to create a polyline.
You have to include the utility library in your gradle as
compile 'com.google.maps.android:android-maps-utils:0.5'.
Please have a look at my sample Activity and function showCurvedPolyline (LatLng p1, LatLng p2, double k) that constructs dashed curved polyline between two points. The last parameter k defines curvature of the polyline, it can be >0 and <=1. In my example I used k=0.5
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {
private GoogleMap mMap;
private LatLng sydney1;
private LatLng sydney2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
mMap.getUiSettings().setZoomControlsEnabled(true);
// Add a marker in Sydney and move the camera
sydney1 = new LatLng(-33.904438,151.249852);
sydney2 = new LatLng(-33.905823,151.252422);
mMap.addMarker(new MarkerOptions().position(sydney1)
.draggable(false).visible(true).title("Marker in Sydney 1"));
mMap.addMarker(new MarkerOptions().position(sydney2)
.draggable(false).visible(true).title("Marker in Sydney 2"));
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(sydney1, 16F));
this.showCurvedPolyline(sydney1,sydney2, 0.5);
}
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));
}
}
You can download a sample project with complete code from GitHub
https://github.com/xomena-so/so43305664
Just replace my API key with yours in the app/src/debug/res/values/google_maps_api.xml
Thanks to #xomena for the great answer. But it has just one little bug. Sometimes, it's arc becoming like a circle. I made a few debugging and see that, we are always using h + 90.0 for heading value at the 12. line of the method. We can solve this by changing that line like this:
LatLng c = SphericalUtil.computeOffset(p, x, h > 40 ? h + 90.0 : h - 90.0);
From now, you probably not encounter this problem again.
I had the same problem of crooked curved line when I am drawing curve in solid line. After few hours of searching on the internet and trying the different solution. Finally, I came up with the solution (NOT a proper solution but target can be achieved) by using Polygon instead of Polyline. I have modified the above method showCurvedPolyline() to draw a smooth curve and the curve direction will always be in upward direction. Below screenshots are the final result of my modified version.
fun drawCurveOnMap(googleMap: GoogleMap, latLng1: LatLng, latLng2: LatLng) {
//Adding marker is optional here, you can move out from here.
googleMap.addMarker(
MarkerOptions().position(latLng1).icon(BitmapDescriptorFactory.defaultMarker()))
googleMap.addMarker(
MarkerOptions().position(latLng2).icon(BitmapDescriptorFactory.defaultMarker()))
val k = 0.5 //curve radius
var h = SphericalUtil.computeHeading(latLng1, latLng2)
var d = 0.0
val p: LatLng?
//The if..else block is for swapping the heading, offset and distance
//to draw curve always in the upward direction
if (h < 0) {
d = SphericalUtil.computeDistanceBetween(latLng2, latLng1)
h = SphericalUtil.computeHeading(latLng2, latLng1)
//Midpoint position
p = SphericalUtil.computeOffset(latLng2, d * 0.5, h)
} else {
d = SphericalUtil.computeDistanceBetween(latLng1, latLng2)
//Midpoint position
p = SphericalUtil.computeOffset(latLng1, d * 0.5, h)
}
//Apply some mathematics to calculate position of the circle center
val x = (1 - k * k) * d * 0.5 / (2 * k)
val r = (1 + k * k) * d * 0.5 / (2 * k)
val c = SphericalUtil.computeOffset(p, x, h + 90.0)
//Calculate heading between circle center and two points
val h1 = SphericalUtil.computeHeading(c, latLng1)
val h2 = SphericalUtil.computeHeading(c, latLng2)
//Calculate positions of points on circle border and add them to polyline options
val numberOfPoints = 1000 //more numberOfPoints more smooth curve you will get
val step = (h2 - h1) / numberOfPoints
//Create PolygonOptions object to draw on map
val polygon = PolygonOptions()
//Create a temporary list of LatLng to store the points that's being drawn on map for curve
val temp = arrayListOf<LatLng>()
//iterate the numberOfPoints and add the LatLng to PolygonOptions to draw curve
//and save in temp list to add again reversely in PolygonOptions
for (i in 0 until numberOfPoints) {
val latlng = SphericalUtil.computeOffset(c, r, h1 + i * step)
polygon.add(latlng) //Adding in PolygonOptions
temp.add(latlng) //Storing in temp list to add again in reverse order
}
//iterate the temp list in reverse order and add in PolygonOptions
for (i in (temp.size - 1) downTo 1) {
polygon.add(temp[i])
}
polygon.strokeColor(Color.BLUE)
polygon.strokeWidth(12f)
polygon.strokePattern(listOf(Dash(30f), Gap(50f))) //Skip if you want solid line
googleMap.addPolygon(polygon)
temp.clear() //clear the temp list
}
Why are we adding temp list again in reverse order in PolygonOptions?
If we do not add LatLng again in PolygonOptions in reverse order, the googleMap.addPolygon() will close the path and the final result will be look like below.
TIPS:
If you want the curve is more in circular shape, increase the value of k. like k = 0.75
Thanks #xomena for the solution above. It works beautifully in most cases. But there needs some improvement:
When k == 1, x will be 0 and midpoint (p) will be the same as mid curve point (c). That means it should be a straight line, but then when you calculate the step, it's not Zero so the final result is a half-circle curve, which is ambiguous with the above condition.
When the curve is long enough, let say LIMIT = 1000km, each calculation in h1 + i * step inside the loop make a tiny error to the correct value (due to java double calculation error I guess). Then the start and end points of the polyline not exactly match with start and end coordinations. Moreover, the curvature of the polyline is unpredictable, base on my research, the reason can be the curvature of the Earth's surface that can make your calculation base on heading not correct.
My quick fix is to reset the step to 0 if k == 1 to make it a straight line. For the second problem, if the distance between 2 points is greater than a LIMIT of 1000km, drawing a straight line with k = 1 will be a safer choice to me.
how to make multiple polygon on Google Map I am using
List<lat long> data = new Array List<Lat Long>();
but its create only one polygon when we draw another then last polygon deleted so anyone please help me thanks in advance
You can define a common method to draw polygon on google maps like this:
public PolygonOptions addPolygon(ArrayList < LatLng > arg) {
LatLng[] data = arg.toArray();
PolygonOptions polygonOptions;
for (int i = 0; i <= data.length; i++) {
polygonOptions = new PolygonOptions();
polygonOptions.add(data[i], data[i + 1], data[i + 2])).strokeColor(Color.RED).strokeWidth(2);
polygonOptions.fillColor(Color.parseColor("#51000000"));
return polygonOptions;
}
}
and then add it to your GoogleMap like this:
yourGoogleMap.addPolygon(addPolygon(data));
I am adding a Polygon like this:
PolygonOptions options = new PolygonOptions();
for (int x = 0; x <= 360; x++) {
//get LatLng ll
options.add(ll);
}
options.strokeColor(Color.BLUE);
options.strokeWidth(2);
options.fillColor(Color.CYAN);
map.addPolygon(options);
What i get is a blue stroke polygon(circle). But I am not able to fill it with a color(it just empty). What am i missing?
Thank You
Make sure that the vertices are added in counterclockwise order as given in the docs.
According to the Docs, to fill the polygon with color, the vertices should be added in clockwise order. If you want to make holes, they should be added in counter-clockwise order
List<GeoPoint> geoPoints = new ArrayList<>();
//clockwise
geoPoints.add(new GeoPoint(-8.146242825034385, -29.267578125));
geoPoints.add(new GeoPoint(-12.8974891, -25.3125));
geoPoints.add(new GeoPoint(-23.40276490, -33.585937499999));
geoPoints.add(new GeoPoint(-17.895114303, -40.51757812));
Polygon polygon = new Polygon(); //see note below
geoPoints.add(geoPoints.get(0)); //forces the loop to close(connect last point to first point)
polygon.getFillPaint().setColor(Color.RED); //set fill color,
polygon.setPoints(geoPoints);
//polygons supports holes too, points should be in a counter-clockwise order
// List<List<GeoPoint>> holes = new ArrayList<>();
// holes.add(geoPoints); //HERE geopoints has to be a different list from above
// polygon.setHoles(holes);
The code below doesn't work with Google Maps API v2. The polygons (outer and inner polygons) are drawn with the right border, but the fill color of the outer one is not drawn.
PolygonOptions polygonOptions = new PolygonOptions();
polygonOptions.add(outerCoordinates);
polygonOptions.addHole(Arrays.asList(innerCoordinates));
polygonOptions.fillColor(Color.BLUE);
polygonOptions.strokeWidth(1.0f);
Does anybody face the same problem?
Check whether there is a requirement that polygon coordinates have to be clockwise (or counterclockwise) ordered. Try to change the order.
The vertices must be added in counterclockwise order. Reference
I wrote a function to determinate if a List<LatLng> is clockwise. The code is an implementation of this answer:
public boolean isClockwise(List<LatLng> region) {
final int size = region.size();
LatLng a = region.get(size - 1);
double aux = 0;
for (int i = 0; i < size; i++) {
LatLng b = region.get(i);
aux += (b.latitude - a.latitude) * (b.longitude + a.longitude);
a = b;
}
return aux <= 0;
}
Before adding the polygon points put these three lines:
if (isClockwise(polygon)) {
Collections.reverse(polygon);
}