I was trying to plot a heatmap on Android device using "Google Map" with the help of tutorial as described here on Google developers, using Android utility library
Using the sample code as described in the tutorial, I implemented the heatmap as below:
As you can see, the heat map locations are displayed in Green circles and dots, but actually, I wanted to achieve something like below:
That is connecting the heat map via a line to the current location.
Any idea or help?
You can use SphericalUtil.interpolate() from Google Maps Android API Utility Library to get additional points between your source points and sent it to HeatmapTileProvider to get "heat map line". For example, with this code:
#Override
public void onMapReady(GoogleMap googleMap) {
mGoogleMap = googleMap;
// Create the gradient.
int[] colors = {
Color.rgb(102, 225, 0), // green
Color.rgb(255, 0, 0) // red
};
float[] startPoints = {
0.2f, 1f
};
Gradient gradient = new Gradient(colors, startPoints);
final List<LatLng> sourcePolyPoints = new ArrayList<>();
sourcePolyPoints.add(new LatLng(28.537266, 77.208099));
sourcePolyPoints.add(new LatLng(28.536965, 77.209571));
sourcePolyPoints.add(new LatLng(28.536786, 77.209989));
sourcePolyPoints.add(new LatLng(28.537886, 77.210205));
sourcePolyPoints.add(new LatLng(28.537886, 77.210205));
final List<LatLng> interpolatedPolyPoints = new ArrayList<>();
for (int ixPoint = 0; ixPoint < sourcePolyPoints.size() - 1; ixPoint++) {
int nInterpolated = 50;
for (int ixInterpolated = 0; ixInterpolated < nInterpolated; ixInterpolated++) {
LatLng interpolatedPoint = SphericalUtil.interpolate(sourcePolyPoints.get(ixPoint),
sourcePolyPoints.get(ixPoint + 1), (double) ixInterpolated / (double) nInterpolated);
interpolatedPolyPoints.add(interpolatedPoint);
}
}
// Create the tile provider.
mProvider = new HeatmapTileProvider.Builder()
.data(interpolatedPolyPoints)
.gradient(gradient)
.build();
// Add the tile overlay to the map.
mOverlay = mGoogleMap.addTileOverlay(new TileOverlayOptions().tileProvider(mProvider));
mGoogleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(28.536965, 77.209571), 16));
}
you get smooth "heatmap line" between your source points, like that:
You can adjust color and width of "heatmap line" by HeatmapTileProvider parameters. And if you need polyline only on road you can use Snap to Road part of Google Maps Roads API or examples provided in Waleed Asim comments.
Related
I have added current location via google map routing with
Routing routing = new Routing.Builder()
.travelMode(Routing.TravelMode.DRIVING)
.key(getResources().getString(R.string.google_maps_api))
.withListener(this)
.waypoints(new LatLng(mLastKnownLocation.getLatitude(), mLastKnownLocation.getLongitude()), site_location)
.alternativeRoutes(false)
.build();
routing.execute();
#Override
public void onRoutingSuccess(ArrayList<Route> route, int shortestRouteIndex) {
if (polylines.size() > 0) {
for (Polyline poly : polylines) {
poly.remove();
}
}
polylines = new ArrayList<>();
//add route(s) to the map.
for (int i = 0; i < route.size(); i++) {
//In case of more than 5 alternative routes
int colorIndex = i % COLORS.length;
PolylineOptions polyOptions = new PolylineOptions();
polyOptions.color(getResources().getColor(COLORS[colorIndex]));
polyOptions.width(10 + i * 13);
polyOptions.addAll(route.get(i).getPoints());
Polyline polyline = googleMap.addPolyline(polyOptions);
polylines.add(polyline);
int distance = route.get(i).getDistanceValue();
if (distance < 1000){
totalKm.setText( distance+" Metres");
}else {
totalKm.setText( (distance/1000) +" km");
}
}
LatLngBounds.Builder builder = new LatLngBounds.Builder();
builder.include(new LatLng(mLastKnownLocation.getLatitude(), mLastKnownLocation.getLongitude()));
builder.include(site_marker.getPosition());
LatLngBounds bounds = builder.build();
CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, 100);
googleMap.animateCamera(cu);
}
THis displays a driving directions like
But am trying to display the default google map driving icon with zoomed view like
How do i proceed to add such a map while still retaining the polylines to show driving view.
Jinesh Francis totally right in his answer: you should either run the default map Google Maps application through intent or modify the standard MapView (or MapFragment).
TLDR;
If you chose the second way - easiest approach is to use standard classes of Android Google Maps API to create view like in your example (other way is to create MapView-based custom view).
At first read carefully p 3.2.4 Restrictions Against Misusing the Services (d) of Google Maps Platform Terms of Service:
(d) No Re-Creating Google Products or Features. Customer will not use
the Services to create a product or service with features that are
substantially similar to or that re-create the features of another
Google product or service. Customer’s product or service must contain
substantial, independent value and features beyond the Google products
or services. For example, Customer will not: (i) re-distribute the
Google Maps Core Services or pass them off as if they were Customer’s
services; (ii) create a substitute of the Google Maps Core Services,
Google Maps, or Google Maps mobile apps, or their features; (iii) use
the Google Maps Core Services in a listings or directory service or to
create or augment an advertising product; (iv) combine data from the
Directions API, Geolocation API, and Maps SDK for Android to create
real-time navigation functionality substantially similar to the
functionality provided by the Google Maps for Android mobile app.
and if you not violate Terms of Service you can do what you want with that steps/tasks:
1) get user current location;
2) get a route path segment nearest to user current location (because user location rarely exactly on road);
3) get a azimuth (bearing) of this segment;
4) show map with route path and user current position marker with appropriate tilt and rotation according path segment bearing.
Task 1 can be solved like in this answer of Axxiss:
private final LocationListener mLocationListener = new LocationListener() {
#Override
public void onLocationChanged(final Location location) {
//your code here
}
};
Task 2 can be solved via PolyUtil.isLocationOnPath() like in that answer:
private LatLng getMarkerProjectionOnSegment(LatLng carPos, List<LatLng> segment, Projection projection) {
LatLng markerProjection = null;
Point carPosOnScreen = projection.toScreenLocation(carPos);
Point p1 = projection.toScreenLocation(segment.get(0));
Point p2 = projection.toScreenLocation(segment.get(1));
Point carPosOnSegment = new Point();
float denominator = (p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y);
// p1 and p2 are the same
if (Math.abs(denominator) <= 1E-10) {
markerProjection = segment.get(0);
} else {
float t = (carPosOnScreen.x * (p2.x - p1.x) - (p2.x - p1.x) * p1.x
+ carPosOnScreen.y * (p2.y - p1.y) - (p2.y - p1.y) * p1.y) / denominator;
carPosOnSegment.x = (int) (p1.x + (p2.x - p1.x) * t);
carPosOnSegment.y = (int) (p1.y + (p2.y - p1.y) * t);
markerProjection = projection.fromScreenLocation(carPosOnSegment);
}
return markerProjection;
}
Task 3 can be solved with code like that:
private float getBearing(LatLng begin, LatLng end) {
double dLon = (end.longitude - begin.longitude);
double x = Math.sin(Math.toRadians(dLon)) * Math.cos(Math.toRadians(end.latitude));
double y = Math.cos(Math.toRadians(begin.latitude))*Math.sin(Math.toRadians(end.latitude))
- Math.sin(Math.toRadians(begin.latitude))*Math.cos(Math.toRadians(end.latitude)) * Math.cos(Math.toRadians(dLon));
double bearing = Math.toDegrees((Math.atan2(x, y)));
return (float) bearing;
}
where begin and end is begin and end of current route path segment.
Task 4 can be solved with code like that:
as marker you can use vector drawable of north oriented arrow like that:
ic_up_arrow_circle.xml (also you can adjust transparency and colors):
<vector android:height="24dp" android:viewportHeight="93.934"
android:viewportWidth="93.934"
android:width="24dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<path
android:fillColor="#8fFF0000"
android:pathData="m0,46.9666c0,25.939 21.028,46.967 46.967,46.967c25.939,-0 46.967,-21.028 46.967,-46.967c0,-25.939 -21.027,-46.967 -46.967,-46.967c-25.939,-0 -46.967,21.028 -46.967,46.967zM78.262,67.4396l-31.295,-16.845l-31.295,16.845l31.295,-51.614l31.295,51.614z"
/>
<path
android:fillColor="#FFFFFF"
android:pathData="M78.262,67.4396l-31.295,-16.845l-31.295,16.845l31.295,-51.614l31.295,51.614z"
/>
</vector>
and you can place it on map with code like that:
public Marker addDirectionMarker(LatLng latLng, float angle) {
Drawable circleDrawable = ContextCompat.getDrawable(getApplicationContext(), R.drawable.ic_up_arrow_in_circle);
BitmapDescriptor markerIcon = getMarkerIconFromDrawable(circleDrawable, 150, 150);
return mGoogleMap.addMarker(new MarkerOptions()
.position(latLng)
.anchor(0.5f, 0.5f)
.rotation(angle)
.flat(true)
.icon(markerIcon)
);
}
where 150 is marker size in pixels. NB! You need flat marker for its rotation and tilt with map and 0.5f for move marker anchor exactly on its center point.
then you can show all of this on map:
...
CameraPosition cameraPosition = new CameraPosition.Builder()
.target(userPosition)
.tilt(tilt)
.zoom(zoom)
.bearing(bearing)
.build();
mGoogleMap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
...
But if you do only that marker of user current position appeared in the center of screen (because GoogleMap.moveCamera() sets the center exactly at .target()). So, to avoid it you need to shift down the map slightly - in that case user location marker should be appeared at the bottom of screen. For map center shift you need get current map center screen coordinates, then change y coordinate and get new screen center. Something like that:
...
LatLng mapCenter = mGoogleMap.getCameraPosition().target;
Projection projection = mGoogleMap.getProjection();
Point centerPoint = projection.toScreenLocation(mapCenter);
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int displayHeight = displayMetrics.heightPixels;
centerPoint.y = centerPoint.y - (int) (displayHeight / 4.5); // move center down for approx 22%
LatLng newCenterPoint = projection.fromScreenLocation(centerPoint);
mGoogleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(newCenterPoint, zoom));
...
And with all of this stuff, for your route (with zoom = 15 and tilt = 50) you should get something like that:
As you can see, the route path is not exactly on road, so you need to get route path points more precisely than Directions API response. You can get that e.g. via Google Maps Roads API part Snap to Road which
returns the best-fit road geometry for a given set of GPS coordinates.
This service takes up to 100 GPS points collected along a route, and
returns a similar set of data with the points snapped to the most
likely roads the vehicle was traveling along.
like in that answer. If your route path has more than points you need to split in into 100-points portions and process them separately (also Snap to Road API has 2500 request per day per user (IP) and 10 requests per sec. restriction).
And as Jaswant Singh answered you:
need to set a custom marker (with icon same as that blue arrow) on
your current location and move it to the new location every time there
is onLocationChanged() callback is called (Also animate the camera to
that new location).
Also, you need to select zoom and tilt properties according, for example, current user speed: when user drives faster tilt -> 0. And so on. It's not a simple task.
In addition to Jinesh’s answer,
If you still want to add that marker for development, you need to set a custom marker (with icon same as that blue arrow) on your current location and move it to the new location every time there is onLocationChanged() callback is called (Also animate the camera to that new location).
And tilt the map a little to get the exact look of the google maps navigation view, though you won’t get to use all the functionalities but it’s worth to give it a try.
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 set bounding box in mapsforge just like in osmdroid and how do I put a text above or below the pathLayer?
In osmdroid, I usually call the setScrollableAreaLimit() method but in mapsforge there's no such method in the mapView. How do I accomplish this?
And also how do I add a TextOverlay below or above the PathLayer?
//Bounding Box
maxScrollableLimit = new BoundingBox(14.7882,121.1421,14.3469,120.8990);
...
private PathLayer createPathLayerFirst(PathWrapper response) {
Style style = Style.builder()
.generalization(Style.GENERALIZATION_SMALL)
.strokeColor(0x9900cc33)
.strokeWidth(4 * getResources().getDisplayMetrics().density)
.build();
PathLayer pathLayer = new PathLayer(mapView.map(), style);
List<GeoPoint> geoPoints = new ArrayList<>();
PointList pointList = response.getPoints();
for (int i = 0; i < pointList.getSize(); i++)
geoPoints.add(new GeoPoint(pointList.getLatitude(i), pointList.getLongitude(i)));
pathLayer.setPoints(geoPoints);
return pathLayer;
}
From the code you provide, it is not clear if you looked at the mapsforge docs at all. Do so first, then return to my answer.
For setting map limits, add the following code to your onStart() method:
mapView.getModel().mapViewPosition.setMapLimit(this.getBoundingBox());
And in the same class, have the following method ready:
private BoundingBox getBoundingBox() {
final double MINLAT = Double.valueOf(res.getString(R.string.mapminlat));
final double MINLON = Double.valueOf(res.getString(R.string.mapminlon));
final double MAXLAT = Double.valueOf(res.getString(R.string.mapmaxlat));
final double MAXLON = Double.valueOf(res.getString(R.string.mapmaxlon));
return new BoundingBox(MINLAT, MINLON, MAXLAT, MAXLON);
}
For adding a layer to your mapview do the following:
mapView.getLayerManager().getLayers().add(layer);
For creating a layer, see the docs. Take a special look at the examples; maybe the LabelLayer is what you are looking for.
I'm trying to show a ground overlay with markers on it to my users. I'm trying to restrain the view to only this image placed on the map. I want the user to only see the image as a ground overlay placed on the map and not be able to go to the surrounding map. And if they go over the edge, the gestures will be blocked.
I want something like this:
I don't want this:
show-only-ground-overlays-map-android or this:
I tried to set my map.setLatLngBoundsForCameraTarget() to my image bounds but the result is something like the previous image...
The next thing I tried is to set a bunch of LatLng objects all around the ground overlay and check with curScreen.contains(customMapDetectionPoints.get(LatLng Object)) to see if they appear on the viewport. It's does work but I can't stop the camera to go over the edge...
Here my test code so far :
private GroundOverlay groundOverlay;
private GoogleMap globalMap;
private final int DETECTION_POINTS_CUSTOM_MAP = 20;
private List<LatLng> customMapDetectionPoints = new ArrayList<>();
//Fully Working as suppose to
#Override
public void onMapReady(GoogleMap map) {
//Other Stuff...
LatLngBounds mapBounds = groundOverlay.getBounds();
map.setLatLngBoundsForCameraTarget(mapBounds);
globalMap = map;
LatLng northwest = new LatLng( mapBounds.northeast.latitude, mapBounds.southwest.longitude);
LatLng northeast = mapBounds.northeast;
LatLng southeast = new LatLng( mapBounds.southwest.latitude, mapBounds.northeast.longitude);
LatLng southwest = mapBounds.southwest;
//My ground overlay is rectangle so I don't need to follow a path or something like that
setDetectionPoints(northwest, southwest);
setDetectionPoints(northeast, southeast);
setDetectionPoints(northwest, northeast);
setDetectionPoints(southwest, southeast);
map.setOnCameraMoveStartedListener(new GoogleMap.OnCameraMoveStartedListener() {
#Override
public void onCameraMoveStarted(int i) {
LatLngBounds curScreen = globalMap.getProjection().getVisibleRegion().latLngBounds;
CameraPosition cameraPosition = globalMap.getCameraPosition();
for (int x =0;x<customMapDetectionPoints.size();x++) {
if (curScreen.contains(customMapDetectionPoints.get(x))) {
cancelMapMovement(cameraPosition);
Log.d("OUT", "Ground Overlay is outside viewport");
return;
} else {
globalMap.getUiSettings().setAllGesturesEnabled(true);
Log.d("IN", "Ground Overlay is inside viewport");
}
}
}
});
//Add 20 new location between two location
//Fully Working as suppose to
public void setDetectionPoints(LatLng fromPos, LatLng toPos) {
double pointLatitude = fromPos.latitude;
double pointLongitude = fromPos.longitude;
double addingValue;
if (fromPos.latitude == toPos.latitude) {
addingValue = (toPos.longitude - fromPos.longitude)/DETECTION_POINTS_CUSTOM_MAP;
for (int i = 0; i < DETECTION_POINTS_CUSTOM_MAP; i++) {
pointLongitude += addingValue;
LatLng pointsPos = new LatLng(pointLatitude, pointLongitude);
customMapDetectionPoints.add(pointsPos);
}
} else if (fromPos.longitude == toPos.longitude) {
addingValue = (toPos.latitude - fromPos.latitude)/DETECTION_POINTS_CUSTOM_MAP;
for (int i = 0; i < DETECTION_POINTS_CUSTOM_MAP; i++) {
pointLatitude += addingValue;
LatLng pointsPos = new LatLng(pointLatitude, pointLongitude);
customMapDetectionPoints.add(pointsPos);
}
}
}
//The problem is here!
public void cancelMapMovement(CameraPosition camPos ) {
//HOW CAN I STOP THE MOVEMENT OVER THE GROUND OVERLAY EDGE
//And make sure that the user dosen't see over the edge
globalMap.getUiSettings().setAllGesturesEnabled(false);
globalMap.moveCamera(CameraUpdateFactory.newCameraPosition(camPos));
}
At this point I think I have two possible solutions:
1- Only use the setLatLngBoundsForCameraTarget() function and set a offset or margin to the camera. But is it possible and will it work for my use case ?
2- Solve my camera restriction problem with the code already written
Thanks for helping! Suggest other solution if you find one!
I will provide more info if wanted.
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);
}