Limit camera only on a ground overlay? Google Map Android API v2 - android

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.

Related

Xamarin.Android Google Maps is blured on navigation

I am building a car navigation application in Xamarin.Android (native not forms). I had read a lot, and follow instructions I found on how to add the map in the application and also how to use the location services, either with the FusedLocationProvider or the NavigationManager. I decided to use the NavigationManager since it looks more accurate because of the number of decimal digits (14) in the LatLng. All good up to now. I am testing my app and while the marker and the map are moving, in order to follow the car's direction, the map is blurred (see the attached pictures), it looks like it does not have the appropriate time to get refreshed.
What I am doing in order to move the camera and the marker?
1. OnLocationChanged from the LocationManager I am calling the UpdateCameraBearing function
internal static void UpdateCameraBearing(float bearing, Location newLocation)
{
if (Map == null)
return;
// Save current zoom
int originalZoom = (int)Map.CameraPosition.Zoom;
if (!startingZoom.HasValue)
{
startingZoom = originalZoom = MapZoomDef;
}
LastLocation = newLocation;
LatLng newPosition = new LatLng(newLocation.Latitude, newLocation.Longitude);
CameraPosition camPos = new CameraPosition(newPosition, originalZoom != MapZoomDef ? originalZoom : MapZoomDef, 0, bearing);
try
{
Map.AnimateCamera(CameraUpdateFactory.NewCameraPosition(camPos));
UpdateMarkerPosition(newPosition);
}
catch (Exception ex)
{
Log.Error(TAG, ex.Message);
}
}
This function animates the camera to the new position and also updates the marker position using the UpdateMarkerPosition function as follows
private static void UpdateMarkerPosition(LatLng newPosition)
{
if (null == MapMarker)
{
SetNewMarker(newPosition);
}
else
{
//positionMarker.Visible = true;
//positionMarker.Position = newPosition;
AnimateMarker(newPosition, new LatLngInterpolatorSpherical());
}
}
private static void SetNewMarker(LatLng myPosition)
{
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.SetPosition(myPosition);
markerOptions.SetIcon(BitmapDescriptorFactory.FromResource(Resource.Mipmap.ic_car));
MapMarker = Map.AddMarker(markerOptions);
}
private static void AnimateMarker(LatLng finalPosition, LatLngInterpolatorSpherical latLngInterpolator)
{
Android.OS.Handler handler = new Android.OS.Handler();
long start = Android.OS.SystemClock.UptimeMillis();
LatLng startPosition = MapMarker.Position;
Android.Views.Animations.AccelerateDecelerateInterpolator interpolator = new Android.Views.Animations.AccelerateDecelerateInterpolator();
float durationInMs = 1000;
Java.Lang.Runnable mUpdateGeneration = null;
mUpdateGeneration = new Java.Lang.Runnable(() => {
long elapsed;
float t;
float v;
// Calculate progress using interpolator
elapsed = Android.OS.SystemClock.UptimeMillis() - start;
t = elapsed / durationInMs;
v = interpolator.GetInterpolation(t);
MapMarker.Position = latLngInterpolator.Interpolate(v, startPosition, finalPosition);
// Repeat till progress is complete.
if (t < 1)
{
// Post again 16ms later.
handler.PostDelayed(mUpdateGeneration, 16);
}
});
handler.Post(mUpdateGeneration);
}
The UpdateMarkerPosition function checks if the marker exists and if not (this is the first time) it creates it, otherwise it calls the AnimateMarker function where I am using an Interpolator in order to simulate a smooth marker movement.
Last but not least the LocationManager.RequestLocationUpdates is configured with 1-second minimum time and 1-meter minimum Distance.
I will appreciate any suggestions on how to solve the problem...
enter image description here
enter image description here

How to visible marker like default android google map places icon

I want to visible marker like default google map places icon visibility. In the default map, icons visibility changed based on map camera zooming level and camera position. That particular area icon was visible others displaying while I changing the camera position. Now I fetched data from SQLite database for the visible region but I removed all marker from the map and added again. So marker flickering during this process (Remove and add again).
My Code:
#Override
public void onCameraIdle() {
Log.i("TAG", "onCameraIdle");
if (cameraMoveReason == REASON_GESTURE) {
LatLngBounds bounds = mGoogleMap.getProjection().getVisibleRegion().latLngBounds;
double minLat;
double maxLat;
double minLng;
double maxLng;
if (bounds.northeast.latitude > bounds.southwest.latitude) {
minLat = bounds.southwest.latitude;
maxLat = bounds.northeast.latitude;
} else {
minLat = bounds.northeast.latitude;
maxLat = bounds.southwest.latitude;
}
if (bounds.northeast.longitude > bounds.southwest.longitude) {
minLng = bounds.southwest.longitude;
maxLng = bounds.northeast.longitude;
} else {
minLng = bounds.northeast.longitude;
maxLng = bounds.southwest.longitude;
}
LocationDAO locationDAO = new LocationDAO(getActivity());
//Fetching data from SQLite database with latlng bounds
ArrayList<LocationDTO> locationDTOArrayList = locationDAO.getLocations(minLat, maxLat, minLng, maxLng);
googleMap.clear();
for (LocationDTO locationDTO : locationDTOArrayList) {
LatLng latLng = new LatLng(locationDTO.getLatitude(), locationDTO.getLongitude());
Bitmap sourceBitmap = BitmapFactory.decodeResource(activity.getResources(),
R.drawable.ic_location_white);
Bitmap bitmapIcon = changeBitmapColor(sourceBitmap, Color.parseColor(locationDTO.getColor()));
Marker marker = googleMap.addMarker(new MarkerOptions().position(latLng)
.icon(BitmapDescriptorFactory.fromBitmap(bitmapIcon)));
marker.setSnippet(String.valueOf(locationDTOArrayList.indexOf(locationDTO)));
marker.setTag(locationDTOArrayList.indexOf(locationDTO));
}
cameraMoveReason = -1;
}
}
#Override
public void onCameraMoveCanceled() {
Log.i("TAG", "onCameraMoveCanceled");
}
#Override
public void onCameraMoveStarted(int i) {
cameraMoveReason = i;
Log.i("TAG", "onCameraMoveStarted : " + i);
}
Please give some suggestions to achieve this functionality with smooth icon visibility.
Check the video to understand my requirement

How to move camera when marker goes outside of the screen?

I am working on map base application to animate marker. There are one marker which is updated against 30 sec interval from server. Marker always move to center of the Map ,so i close moveCamera marker but when marker move outside the map then marker is not come in map view. so i want to camera move when marker goes from map view
Before setting new position of the marker, check it's new position and current bounds of map view.
LatLng newPosition = new LatLng(...);
boolean contains = mMap.getProjection()
.getVisibleRegion()
.latLngBounds
.contains(newPosition);
if(!contains){
// MOVE CAMERA
}
// UPDATE MARKER POSITION
During the marker's each new position inside map view, marker moves(not
center of map)
Just If next position goes out of view, camera and marker will be centered.
Edit
I created a sample route to simulate each point on map periodically. Route gist
public class SampleRoute {
public static List<LatLng> GetPoints() {
return new ArrayList<>(Arrays.asList(
new LatLng(38.4670419, 27.1647131),
new LatLng(38.4667244, 27.1648277),
new LatLng(38.4666633, 27.1649079),
new LatLng(38.4665983, 27.1648022),
new LatLng(38.4665958, 27.1647843),
new LatLng(38.4665958, 27.1647843),
new LatLng(38.4665809, 27.1646429),
new LatLng(38.4665704, 27.1645506),
new LatLng(38.4665529, 27.1644067),
...
}
}
}
Then i create a method in sample activity that calculates current region's bounds and marker's X, Y points on this region. Activity gist
private void moveCamera(LatLng destination){
Projection projection = mMap.getProjection();
LatLngBounds bounds = projection.getVisibleRegion().latLngBounds;
int boundsTopY = projection.toScreenLocation(bounds.northeast).y;
int boundsBottomY = projection.toScreenLocation(bounds.southwest).y;
int boundsTopX = projection.toScreenLocation(bounds.northeast).x;
int boundsBottomX = projection.toScreenLocation(bounds.southwest).x;
int offsetY = (boundsBottomY - boundsTopY) / 10;
int offsetX = (boundsTopX - boundsBottomX ) / 10;
Point destinationPoint = projection.toScreenLocation(destination);
int destinationX = destinationPoint.x;
int destinationY = destinationPoint.y;
int scrollX = 0;
int scrollY = 0;
if(destinationY <= (boundsTopY + offsetY)){
scrollY = -(Math.abs((boundsTopY + offsetY) - destinationY));
}
else if(destinationY >= (boundsBottomY - offsetY)){
scrollY = (Math.abs(destinationY - (boundsBottomY - offsetY)));
}
if(destinationX >= (boundsTopX - offsetX)){
scrollX = (Math.abs(destinationX - (boundsTopX - offsetX)));
}
else if(destinationX <= (boundsBottomX + offsetX)){
scrollX = -(Math.abs((boundsBottomX + offsetX) - destinationX));
}
mMap.animateCamera(CameraUpdateFactory.scrollBy(scrollX, scrollY));
mMarker.setPosition(destination);
}
And then started to simulate points
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
moveCamera(mPoints.get(mCurrentPos));
if(++mCurrentPos < mPoints.size()){
mHandler.postDelayed(this, 1500);
}
}
}, 1500);
I tried and it's working well on me
So, if i understand you correctly and it works for you too then i could explain.
When marker location is updated you can animate the camera to the marker position. Following sample code may help you
LatLng definedLoc = new LatLng(latitudeValue, longitudeValue);
CameraPosition cameraPosition = new CameraPosition.Builder().target(definedLoc).zoom(13.0F).build();
map.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
You can animate the camera to the Marker position if the map bounds does not contain the marker using a GoogleMap.OnCameraChangeListener:
private Marker marker;
// ...
#Override
public void onCameraChange(final CameraPosition cameraPosition) {
ensureMarkerOnBounds();
}
private void ensureMarkerOnBounds() {
if (marker != null) {
if (!mMap.getProjection().getVisibleRegion().latLngBounds.contains(marker.getPosition())) {
mMap.animateCamera(CameraUpdateFactory.newLatLng(marker.getPosition()));
}
}
}
// This is the function that you use to move your marker
private void moveMarker (Marker marker) {
// ... Your code to move your marker
ensureMarkerOnBounds();
}

Androids map - Check if center camera is within bounds

I want to create a method to see if the center of the camera co-ords is within the bounds of an area, if so then do something.
When i try this i am getting error: Operator ! cannot be applied to LatLngBounds.
I have also tried if(temp != new LatLngBounds(bounds1, bounds2)) but got the same error.
Here is my method
public GoogleMap.OnCameraChangeListener getCameraChangeListener()
{
return new GoogleMap.OnCameraChangeListener()
{
#Override
public void onCameraChange(CameraPosition cameraPosition)
{
LatLng temp = new LatLng(cameraPosition.target.latitude, cameraPosition.target.longitude);
//Northwest corner of bounds
LatLng bounds1 = new LatLng(-41.467668522, 173.03190229);
//Southwest corner of bounds
LatLng bounds2 = new LatLng(-40.095127348, 177.97574994);
LatLngBounds outside = new LatLngBounds(bounds1, bounds2);
//If the camera is within the bounds
if(temp != outside)
{
//do something
}
}
};
}
I think you mean northeast not northwest? Otherwise it would just be a line.
LatLngBounds has a Contains method which allows for
if (outside.contains(temp){
//do something
}
Outside is a bit of a misleading name for that variable though.

Android maps auto zooming

Hi Im having a little issue with displaying points on a map.
I use an Arraylist to store multiple lat/lng values and then do a for loop to add the point and auto zoom. Everything works fine when there are 2 or more markers. The problem is when only 1 marker is added it zooms in too close.
Anyone know how to resolve this?
public static void processMap()
{
for (int i = 0; i < lat.size(); i++)
{
MarkerOptions markerOptions = new MarkerOptions();
LatLng latLng = new LatLng(lat.get(i), lng.get(i));
markerOptions.position(latLng);
markerOptions.title("title");
markerOptions.snippet("description");
mMap.addMarker(markerOptions);
bounds.include(new LatLng(lat.get(i), lng.get(i)));
}
mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds.build(), 150));
}
Updated code
public static void processMap()
{
int num = 0;
double lat2 = 0;
double lng2 = 0;
for (int l = 0; l < lat.size(); l++)
{
lat2 = lat.get(l);
lng2 = lng.get(l);
LatLng latLng = new LatLng(lat2, lng2);
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(latLng);
markerOptions.title(title.get(l));
markerOptions.snippet(description.get(l));
mMap.addMarker(markerOptions);
bounds.include(new LatLng(lat2, lng2));
num++;
}
if (num == 1)
{
// if only 1 marker
LatLng latLng2 = new LatLng(lat2, lng2);
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng2, 16));
}
else
{
// more than 1 marker
mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds.build(), 150));
}
}
Hi sorry I didn't reply earlier I was attempting to fix the problem. I managed to fix it, but is this the correct way of going about it?
The edit you made should fix your problem. Anyway you don't need to set new LatLng if you only have 1 marker. Passing the bound should do. I would make this little edit:
if (num == 1)
{
// if only 1 marker
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(bounds.build(), 16));
}
else
{
// more than 1 marker
mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds.build(), 150));
}
Hope it helps. Good luck!
Your code does not really tell why you are using .newLatLngBounds(), but this will center the map on your given bounding box and respecting the given 150px padding around the box.
The zoom is then adapted according to the elements inside the bounding box to show all of them. When there is only one marker inside the box, it will zoom to it (and probably too close). The docs say that the map will be centered "at the greatest possible zoom level".
So to prevent this, I would choose a good zoom level for the first marker, add it, move the camera with moveCamera(...) and after that continue with your code when there are other markers left.

Categories

Resources