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.
Related
I am using clustering for maker representation on map. But when user click on any cluster item. It bounds all latlng within cluster. this is my code:
#Override
public boolean onClusterClick(Cluster<MapMakerModel> cluster) {
String firstName = cluster.getItems().iterator().next().getTitle();
showSnackbar(cluster.getSize() + " (including " + firstName + ")");
// Zoom in the cluster. Need to create LatLngBounds and including all the cluster items
// inside of bounds, then animate to center of the bounds.
// Create the builder to collect all essential cluster items for the bounds.
LatLngBounds.Builder builder = LatLngBounds.builder();
for (ClusterItem item : cluster.getItems()) {
builder.include(item.getPosition());
}
// Get the LatLngBounds
final LatLngBounds bounds = builder.build();
// Animate camera to the bounds
try {
mMap.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 100));
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
so when this code is called it bound all latlng within that cluster.that is right but it also rotate camera from user angle to NS angle which I don't want to do.
How I can archive this??
Returned by CameraUpdateFactory.newLatLngBounds() method CameraUpdate object has
a bearing of 0 and a tilt of 0.
But you can get current (before set to bounds) bearing (probably tilt too) and set it AFTER camera animation. And not exactly after if you set duration of bounding box zoom animation to 0 and do all animation in next steps. Something like that:
...
// Get the LatLngBounds
final LatLngBounds bounds = builder.build();
// Get bearing and tilt
final float bearing = mGoogleMap.getCameraPosition().bearing;
final float tilt = mGoogleMap.getCameraPosition().tilt;
// Animate camera to the bounds
try {
mMap.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 100) ,0 /*duration of "set to bounds" animation */, new GoogleMap.CancelableCallback(){
#Override
public void onCancel() {
}
#Override
public void onFinish() {
mMap.animateCamera(CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder()
.bearing(bearing)
.bearing(tilt)
.build()), 1000 /*duration of "set bearing and tilt" animation */, null);
}
});
} catch (Exception e) {
e.printStackTrace();
}
...
Or you need to calculate your cluster LatLngBounds manually and use CameraUpdateFactory.newCameraPosition()
instead of CameraUpdateFactory.newLatLngBounds().
EXAMPLE IMAGE
I put many circles on the map, and I wish to these circles have their own OncircleClick Listener
but the problem is, I can regist only one circle click listener on the googleMap, and This Listener is shared by every circle, so every Times I click any circles, same listener event would occured.
Could you let me know how to make each circles can have their own On circle click Listener? thank you.
here is my tried code :
private void drawCircle(LatLng point, boolean isOverThreshold, final Bundle results){
GoogleMap.OnCircleClickListener onCircleClickListener = new GoogleMap.OnCircleClickListener() {
#Override
public void onCircleClick(Circle circle) {
int sixty_one = results.getInt("60hz_1");
int eighty_one = results.getInt("180hz_1");
int sixty_two = results.getInt("60hz_2");
int eighty_two = results.getInt("180hz_2");
int sixty_three = results.getInt("60hz_3");
int eighty_three = results.getInt("180hz_3");
double speed = results.getDouble("speed");
Toast.makeText(ReplayActivity.this, "CH1: ("+sixty_one+","+eighty_one+") \n"+" CH2: (" + sixty_two+","+eighty_two+") \n" + "CH3: ("+sixty_three+","+eighty_three+")\n speed:"+speed+"m/s )",Toast.LENGTH_SHORT).show();
Log.d("gd","circle clicked!");
}
};
// Instantiating CircleOptions to draw a circle around the marker
CircleOptions circleOptions = new CircleOptions();
// Specifying the center of the circle
circleOptions.center(point);
(....)
// Adding the circle to the GoogleMap
map.addCircle(circleOptions);
map.setOnCircleClickListener(onCircleClickListener);
//but this oncircleListener is shared by every circle click event..
}
You can use Circle.setTag() method of created circle object to set, for example the ID of Circle object (or more complex structure) as Tag, and then use Circle.getTag() inside yours onCircleClickListener to get this ID (or more complex structure). Something like that:
private void drawCircle(LatLng point, boolean isOverThreshold, final Bundle results){
GoogleMap.OnCircleClickListener onCircleClickListener = new GoogleMap.OnCircleClickListener() {
#Override
public void onCircleClick(Circle circle) {
// get stored Tag object from passed circle object
YOUR_TAG_OBJECT_CLASS yourTagObjectName = (YOUR_TAG_OBJECT_CLASS)circle.getTag();
if (yourTagObjectName != null) {
// parse it
switch (yourTagObjectName.id) {
case ID_1: ... break;
case ID_2: ... break;
...
}
}
int sixty_one = results.getInt("60hz_1");
int eighty_one = results.getInt("180hz_1");
int sixty_two = results.getInt("60hz_2");
int eighty_two = results.getInt("180hz_2");
int sixty_three = results.getInt("60hz_3");
int eighty_three = results.getInt("180hz_3");
double speed = results.getDouble("speed");
Toast.makeText(ReplayActivity.this, "CH1: ("+sixty_one+","+eighty_one+") \n"+" CH2: (" + sixty_two+","+eighty_two+") \n" + "CH3: ("+sixty_three+","+eighty_three+")\n speed:"+speed+"m/s )",Toast.LENGTH_SHORT).show();
Log.d("gd","circle clicked!");
}
};
// Instantiating CircleOptions to draw a circle around the marker
CircleOptions circleOptions = new CircleOptions();
// Specifying the center of the circle
circleOptions.center(point);
(....)
// Adding the circle to the GoogleMap
Circle circle = map.addCircle(circleOptions); // <- store circle object
circle.setTag(YOUR_TAG_ID_OR_OBJECT); // <- set Tag to stored circle object
map.setOnCircleClickListener(onCircleClickListener);
}
I'm having a bit of a struggle using CameraPosition because I can't have a proper zoom.
For me, a proper zoom would be the distance between a Marker and my current position.
However, I managed to get a proper zoom using CameraUpdateFactory, but the I lost all the other attributes (orientation (looking always north) and bird-eye (45 degrees view)).
I'm balanced between this (doesn't have the right zoom):
CameraPosition cameraPosition = new CameraPosition.Builder()
.target(current_location)
.zoom(mGoogleMap.getCameraPosition().zoom)
.bearing(location.getBearing())
.tilt(birdEyesAngle)
.build();
and this (right zoom, but missing other attributes):
CameraUpdateFactory.newLatLngBounds(bounds_between_two_markers, 10);
Is there any way to have both correct zoom and correct orientation/bird-eye ?
Hope you'll help,
Thanks
Try this:
Get the CameraUpdate object first using the newLatLngBounds method:
CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds_between_two_markers, 10);
The following code I put in my onMapReady() method:
LatLng pos = new LatLng(51.516667, 12.388889);
LatLng pos1 = new LatLng(53.516667, 14.388889);
MarkerOptions markerOptions = setUserMarker(pos);
if(markerOptions != null) {
markerOptions.title(campusLocationName);
mMap.addMarker(markerOptions);
}
LatLngBounds.Builder b = new LatLngBounds.Builder();
b.include(pos);
b.include(pos1);
CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(b.build(), 20);
mMap.animateCamera(cu, 10, new GoogleMap.CancelableCallback() {
#Override
public void onFinish() {
Log.e(TAG, "Start animate onFinish");
CameraPosition cp = new CameraPosition.Builder()
.zoom(mMap.getCameraPosition().zoom)
.target(pos)
.tilt(45.0f)
.bearing(35.0f)
.build();
mMap.animateCamera(CameraUpdateFactory.newCameraPosition(cp));
// mMap.moveCamera(CameraUpdateFactory.newCameraPosition(cp));
}
#Override
public void onCancel() {
Log.e(TAG, "Start animate onCancel");
}
});
The result from my device:
Using the CancelableCallBack you can make the changes to the camera position as before, but if you do not change the zoom factor, the camera keeps the old zoom factor, you just set the bearing and tilt as you like.
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.
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();
}