As per my requirement, I am drawing polygons on google map shown in the image below.(using maps v2)
Now I need to show an alert when user enters that particular polygons.
How to identify if my current location is with in the polygon.
(Need optimized way without draining battery)
Thanks in advance.
Just tried Ray Casting algorithm which identifies point in polygon. This works perfect.
Refer http://en.wikipedia.org/wiki/Point_in_polygon for thesis of Ray-Casting
private boolean isPointInPolygon(LatLng tap, ArrayList<LatLng> vertices) {
int intersectCount = 0;
for (int j = 0; j < vertices.size() - 1; j++) {
if (rayCastIntersect(tap, vertices.get(j), vertices.get(j + 1))) {
intersectCount++;
}
}
return ((intersectCount % 2) == 1); // odd = inside, even = outside;
}
private boolean rayCastIntersect(LatLng tap, LatLng vertA, LatLng vertB) {
double aY = vertA.latitude;
double bY = vertB.latitude;
double aX = vertA.longitude;
double bX = vertB.longitude;
double pY = tap.latitude;
double pX = tap.longitude;
if ((aY > pY && bY > pY) || (aY < pY && bY < pY)
|| (aX < pX && bX < pX)) {
return false; // a and b can't both be above or below pt.y, and a or
// b must be east of pt.x
}
double m = (aY - bY) / (aX - bX); // Rise over run
double bee = (-aX) * m + aY; // y = mx + b
double x = (pY - bee) / m; // algebra is neat!
return x > pX;
}
I found ray-casting method unreliable but I ended up using the PolyUtil from google maps.
You need the dependency compile 'com.google.maps.android:android-maps-utils:0.5'
And then the method looks like this
PolyUtil.containsLocation(userLocation, polyPointsList, false);
EDIT
This is the description of this method found in source code
Computes whether the given point lies inside the specified polygon. The polygon is always considered closed, regardless of whether the last point equals the first or not. Inside is defined as not containing the South Pole -- the South Pole is always outside. The polygon is formed of great circle segments if geodesic is true, and of rhumb (loxodromic) segments otherwise.
Refer this link
Polygon Touch detection Google Map API V2
Its RayCasting algorithm, it may help you :)
A brief description about the algorithm:
A horizontal line is drawn from your point to the right, if it intersects the sides of polygon at odd number of times then the point is inside the polygon else outside :)
These wiki links will give you complete idea:
http://en.wikipedia.org/wiki/Point_in_polygon
http://rosettacode.org/wiki/Ray-casting_algorithm
Here is the code in Dart, taken from:
https://github.com/KohlsAdrian/google_maps_utils/blob/master/lib/poly_utils.dart
/// Checks if [point] is inside [polygon]
static bool containsLocationPoly(Point point, List<Point> polygon) {
num ax = 0;
num ay = 0;
num bx = polygon[polygon.length - 1].x - point.x;
num by = polygon[polygon.length - 1].y - point.y;
int depth = 0;
for (int i = 0; i < polygon.length; i++) {
ax = bx;
ay = by;
bx = polygon[i].x - point.x;
by = polygon[i].y - point.y;
if (ay < 0 && by < 0) continue; // both "up" or both "down"
if (ay > 0 && by > 0) continue; // both "up" or both "down"
if (ax < 0 && bx < 0) continue; // both points on left
num lx = ax - ay * (bx - ax) / (by - ay);
if (lx == 0) return true; // point on edge
if (lx > 0) depth++;
}
return (depth & 1) == 1;
}
As per my requirement, I am drawing polygons on google map shown in the image below.(using maps v2)
Now I need to show an alert when user enters that particular polygons.
How to identify if my current location is with in the polygon.
(Need optimized way without draining battery)
Thanks in advance.
Just tried Ray Casting algorithm which identifies point in polygon. This works perfect.
Refer http://en.wikipedia.org/wiki/Point_in_polygon for thesis of Ray-Casting
private boolean isPointInPolygon(LatLng tap, ArrayList<LatLng> vertices) {
int intersectCount = 0;
for (int j = 0; j < vertices.size() - 1; j++) {
if (rayCastIntersect(tap, vertices.get(j), vertices.get(j + 1))) {
intersectCount++;
}
}
return ((intersectCount % 2) == 1); // odd = inside, even = outside;
}
private boolean rayCastIntersect(LatLng tap, LatLng vertA, LatLng vertB) {
double aY = vertA.latitude;
double bY = vertB.latitude;
double aX = vertA.longitude;
double bX = vertB.longitude;
double pY = tap.latitude;
double pX = tap.longitude;
if ((aY > pY && bY > pY) || (aY < pY && bY < pY)
|| (aX < pX && bX < pX)) {
return false; // a and b can't both be above or below pt.y, and a or
// b must be east of pt.x
}
double m = (aY - bY) / (aX - bX); // Rise over run
double bee = (-aX) * m + aY; // y = mx + b
double x = (pY - bee) / m; // algebra is neat!
return x > pX;
}
I found ray-casting method unreliable but I ended up using the PolyUtil from google maps.
You need the dependency compile 'com.google.maps.android:android-maps-utils:0.5'
And then the method looks like this
PolyUtil.containsLocation(userLocation, polyPointsList, false);
EDIT
This is the description of this method found in source code
Computes whether the given point lies inside the specified polygon. The polygon is always considered closed, regardless of whether the last point equals the first or not. Inside is defined as not containing the South Pole -- the South Pole is always outside. The polygon is formed of great circle segments if geodesic is true, and of rhumb (loxodromic) segments otherwise.
Refer this link
Polygon Touch detection Google Map API V2
Its RayCasting algorithm, it may help you :)
A brief description about the algorithm:
A horizontal line is drawn from your point to the right, if it intersects the sides of polygon at odd number of times then the point is inside the polygon else outside :)
These wiki links will give you complete idea:
http://en.wikipedia.org/wiki/Point_in_polygon
http://rosettacode.org/wiki/Ray-casting_algorithm
Here is the code in Dart, taken from:
https://github.com/KohlsAdrian/google_maps_utils/blob/master/lib/poly_utils.dart
/// Checks if [point] is inside [polygon]
static bool containsLocationPoly(Point point, List<Point> polygon) {
num ax = 0;
num ay = 0;
num bx = polygon[polygon.length - 1].x - point.x;
num by = polygon[polygon.length - 1].y - point.y;
int depth = 0;
for (int i = 0; i < polygon.length; i++) {
ax = bx;
ay = by;
bx = polygon[i].x - point.x;
by = polygon[i].y - point.y;
if (ay < 0 && by < 0) continue; // both "up" or both "down"
if (ay > 0 && by > 0) continue; // both "up" or both "down"
if (ax < 0 && bx < 0) continue; // both points on left
num lx = ax - ay * (bx - ax) / (by - ay);
if (lx == 0) return true; // point on edge
if (lx > 0) depth++;
}
return (depth & 1) == 1;
}
As per my requirement, I am drawing polygons on google map shown in the image below.(using maps v2)
Now I need to show an alert when user enters that particular polygons.
How to identify if my current location is with in the polygon.
(Need optimized way without draining battery)
Thanks in advance.
Just tried Ray Casting algorithm which identifies point in polygon. This works perfect.
Refer http://en.wikipedia.org/wiki/Point_in_polygon for thesis of Ray-Casting
private boolean isPointInPolygon(LatLng tap, ArrayList<LatLng> vertices) {
int intersectCount = 0;
for (int j = 0; j < vertices.size() - 1; j++) {
if (rayCastIntersect(tap, vertices.get(j), vertices.get(j + 1))) {
intersectCount++;
}
}
return ((intersectCount % 2) == 1); // odd = inside, even = outside;
}
private boolean rayCastIntersect(LatLng tap, LatLng vertA, LatLng vertB) {
double aY = vertA.latitude;
double bY = vertB.latitude;
double aX = vertA.longitude;
double bX = vertB.longitude;
double pY = tap.latitude;
double pX = tap.longitude;
if ((aY > pY && bY > pY) || (aY < pY && bY < pY)
|| (aX < pX && bX < pX)) {
return false; // a and b can't both be above or below pt.y, and a or
// b must be east of pt.x
}
double m = (aY - bY) / (aX - bX); // Rise over run
double bee = (-aX) * m + aY; // y = mx + b
double x = (pY - bee) / m; // algebra is neat!
return x > pX;
}
I found ray-casting method unreliable but I ended up using the PolyUtil from google maps.
You need the dependency compile 'com.google.maps.android:android-maps-utils:0.5'
And then the method looks like this
PolyUtil.containsLocation(userLocation, polyPointsList, false);
EDIT
This is the description of this method found in source code
Computes whether the given point lies inside the specified polygon. The polygon is always considered closed, regardless of whether the last point equals the first or not. Inside is defined as not containing the South Pole -- the South Pole is always outside. The polygon is formed of great circle segments if geodesic is true, and of rhumb (loxodromic) segments otherwise.
Refer this link
Polygon Touch detection Google Map API V2
Its RayCasting algorithm, it may help you :)
A brief description about the algorithm:
A horizontal line is drawn from your point to the right, if it intersects the sides of polygon at odd number of times then the point is inside the polygon else outside :)
These wiki links will give you complete idea:
http://en.wikipedia.org/wiki/Point_in_polygon
http://rosettacode.org/wiki/Ray-casting_algorithm
Here is the code in Dart, taken from:
https://github.com/KohlsAdrian/google_maps_utils/blob/master/lib/poly_utils.dart
/// Checks if [point] is inside [polygon]
static bool containsLocationPoly(Point point, List<Point> polygon) {
num ax = 0;
num ay = 0;
num bx = polygon[polygon.length - 1].x - point.x;
num by = polygon[polygon.length - 1].y - point.y;
int depth = 0;
for (int i = 0; i < polygon.length; i++) {
ax = bx;
ay = by;
bx = polygon[i].x - point.x;
by = polygon[i].y - point.y;
if (ay < 0 && by < 0) continue; // both "up" or both "down"
if (ay > 0 && by > 0) continue; // both "up" or both "down"
if (ax < 0 && bx < 0) continue; // both points on left
num lx = ax - ay * (bx - ax) / (by - ay);
if (lx == 0) return true; // point on edge
if (lx > 0) depth++;
}
return (depth & 1) == 1;
}
I'm trying to figure out how best to do this, I have a map with one Polygon drawn on it. Since it doesn't seem as though the Google Maps API V2 has a touch detection on a Polygon. I was wonder if it is possible to detect whether the touch point is inside the Polygon? If so then how, my main goal is to outline a state on a map and when the user taps that state it will show more details inside a custom view. As of now I am able to capture the MapOnClick of the map but when the user taps inside the Polygon I want the polygon.getID() set on the Toast. I am a newbie so I apologize if I am not clear enough.
googleMap.setOnMapClickListener(new OnMapClickListener()
{
public void onMapClick(LatLng point)
{
boolean checkPoly = true;
Toast.makeText(MainActivity.this,"The Location is outside of the Area", Toast.LENGTH_LONG).show();
}
});
}
}
catch (Exception e) {
Log.e("APP","Failed", e);
}
Ok this is what I have semi-working so far
private boolean rayCastIntersect(LatLng tap, LatLng vertA, LatLng vertB) {
double aY = vertA.latitude;
double bY = vertB.latitude;
double aX = vertA.longitude;
double bX = vertB.longitude;
double pY = tap.latitude;
double pX = tap.longitude;
if (aY > bY) {
aX = vertB.longitude;
aY = vertB.latitude;
bX = vertA.longitude;
bX = vertA.latitude;
}
System.out.println("aY: "+aY+" aX : "+aX);
System.out.println("bY: "+bY+" bX : "+bX);
if (pX < 0) pX += 360;
if (aX < 0) aX += 360;
if (bX < 0) bX += 360;
if (pY == aY || pY == bY) pY += 0.00000001;
if ((pY > bY || pY < aY) || (pX > Math.max(aX, bX))) return false;
if (pX < Math.min(aX, bX))
return true;
// }
double m = (aX != bX) ? ((bY - aY) / (bX - aX)) : aX;
double bee = (aX != pX) ? ((pY - aY) / (pX - aX)) : aX;
double x = (pY - bee) / m;
return x > pX;
}
}
The issue that I am having is the touch is true to the left of each polygon until it reaches another one. What's wrong with my algorithm that would cause this issue? Any help would be appreciated.
The problem you're trying to solve is the Point in Polygon test.
To help visualize the concept of Ray Casting:
Draw a Polygon on a piece of paper. Then, starting at any random point, draw a straight line to the right of the page. If your line intersected with your polygon an odd number of times, this means your starting point was inside the Polygon.
So, how do you do that in code?
Your polygon is comprised of a list of vertices: ArrayList<Geopoint> vertices. You need to look at each Line Segment individually, and see if your Ray intersects it
private boolean isPointInPolygon(Geopoint tap, ArrayList<Geopoint> vertices) {
int intersectCount = 0;
for(int j=0; j<vertices.size()-1; j++) {
if( rayCastIntersect(tap, vertices.get(j), vertices.get(j+1)) ) {
intersectCount++;
}
}
return (intersectCount%2) == 1); // odd = inside, even = outside;
}
private boolean rayCastIntersect(Geopoint tap, Geopoint vertA, Geopoint vertB) {
double aY = vertA.getLatitude();
double bY = vertB.getLatitude();
double aX = vertA.getLongitude();
double bX = vertB.getLongitude();
double pY = tap.getLatitude();
double pX = tap.getLongitude();
if ( (aY>pY && bY>pY) || (aY<pY && bY<pY) || (aX<pX && bX<pX) ) {
return false; // a and b can't both be above or below pt.y, and a or b must be east of pt.x
}
double m = (aY-bY) / (aX-bX); // Rise over run
double bee = (-aX) * m + aY; // y = mx + b
double x = (pY - bee) / m; // algebra is neat!
return x > pX;
}
The Google Maps Support library now has a static method that does this check for you:
PolyUtil.containsLocation(LatLng point, List<LatLng>polygon, boolean geodesic);
Although the docs don't mention it explicitly in the guide the method is there
Maps Support Library docs
With the release of Google Play Services 8.4.0, the Maps API has included support for adding an OnPolygonClickListener to Polygons. Both polygons, polylines and overlays support similar events.
You just need to call GoogleMap.setOnPolygonClickListener(OnPolygonClickListener listener) to set it up, and correspondingly for the other listeners (setOnPolylineClickListener, &c):
map.setOnPolygonClickListener(new GoogleMap.OnPolygonClickListener() {
#Override
public void onPolygonClick(Polygon polygon) {
// Handle click ...
}
});
Although a bit late, it solves this use case quite nicely.
Though user1504495 has answered in short as I have used it. But instead of using whole Map Utility Library Use this methods.
From your activity class pass params accordingly:
if (area.containsLocation(Touchablelatlong, listLatlong, true))
isMarkerINSide = true;
else
isMarkerINSide = false;
and put following in a Separate class :
/**
* Computes whether the given point lies inside the specified polygon.
* The polygon is always cosidered closed, regardless of whether the last point equals
* the first or not.
* Inside is defined as not containing the South Pole -- the South Pole is always outside.
* The polygon is formed of great circle segments if geodesic is true, and of rhumb
* (loxodromic) segments otherwise.
*/
public static boolean containsLocation(LatLng point, List<LatLng> polygon, boolean geodesic) {
final int size = polygon.size();
if (size == 0) {
return false;
}
double lat3 = toRadians(point.latitude);
double lng3 = toRadians(point.longitude);
LatLng prev = polygon.get(size - 1);
double lat1 = toRadians(prev.latitude);
double lng1 = toRadians(prev.longitude);
int nIntersect = 0;
for (LatLng point2 : polygon) {
double dLng3 = wrap(lng3 - lng1, -PI, PI);
// Special case: point equal to vertex is inside.
if (lat3 == lat1 && dLng3 == 0) {
return true;
}
double lat2 = toRadians(point2.latitude);
double lng2 = toRadians(point2.longitude);
// Offset longitudes by -lng1.
if (intersects(lat1, lat2, wrap(lng2 - lng1, -PI, PI), lat3, dLng3, geodesic)) {
++nIntersect;
}
lat1 = lat2;
lng1 = lng2;
}
return (nIntersect & 1) != 0;
}
/**
* Wraps the given value into the inclusive-exclusive interval between min and max.
* #param n The value to wrap.
* #param min The minimum.
* #param max The maximum.
*/
static double wrap(double n, double min, double max) {
return (n >= min && n < max) ? n : (mod(n - min, max - min) + min);
}
/**
* Returns the non-negative remainder of x / m.
* #param x The operand.
* #param m The modulus.
*/
static double mod(double x, double m) {
return ((x % m) + m) % m;
}
/**
* Computes whether the vertical segment (lat3, lng3) to South Pole intersects the segment
* (lat1, lng1) to (lat2, lng2).
* Longitudes are offset by -lng1; the implicit lng1 becomes 0.
*/
private static boolean intersects(double lat1, double lat2, double lng2,
double lat3, double lng3, boolean geodesic) {
// Both ends on the same side of lng3.
if ((lng3 >= 0 && lng3 >= lng2) || (lng3 < 0 && lng3 < lng2)) {
return false;
}
// Point is South Pole.
if (lat3 <= -PI/2) {
return false;
}
// Any segment end is a pole.
if (lat1 <= -PI/2 || lat2 <= -PI/2 || lat1 >= PI/2 || lat2 >= PI/2) {
return false;
}
if (lng2 <= -PI) {
return false;
}
double linearLat = (lat1 * (lng2 - lng3) + lat2 * lng3) / lng2;
// Northern hemisphere and point under lat-lng line.
if (lat1 >= 0 && lat2 >= 0 && lat3 < linearLat) {
return false;
}
// Southern hemisphere and point above lat-lng line.
if (lat1 <= 0 && lat2 <= 0 && lat3 >= linearLat) {
return true;
}
// North Pole.
if (lat3 >= PI/2) {
return true;
}
// Compare lat3 with latitude on the GC/Rhumb segment corresponding to lng3.
// Compare through a strictly-increasing function (tan() or mercator()) as convenient.
return geodesic ?
tan(lat3) >= tanLatGC(lat1, lat2, lng2, lng3) :
mercator(lat3) >= mercatorLatRhumb(lat1, lat2, lng2, lng3);
}
/**
* Returns tan(latitude-at-lng3) on the great circle (lat1, lng1) to (lat2, lng2). lng1==0.
* See http://williams.best.vwh.net/avform.htm .
*/
private static double tanLatGC(double lat1, double lat2, double lng2, double lng3) {
return (tan(lat1) * sin(lng2 - lng3) + tan(lat2) * sin(lng3)) / sin(lng2);
}
/**
* Returns mercator Y corresponding to latitude.
* See http://en.wikipedia.org/wiki/Mercator_projection .
*/
static double mercator(double lat) {
return log(tan(lat * 0.5 + PI/4));
}
/**
* Returns mercator(latitude-at-lng3) on the Rhumb line (lat1, lng1) to (lat2, lng2). lng1==0.
*/
private static double mercatorLatRhumb(double lat1, double lat2, double lng2, double lng3) {
return (mercator(lat1) * (lng2 - lng3) + mercator(lat2) * lng3) / lng2;
}
Here's a full working example to know if a touch happened on a polygon. Some of the answers are more complicated than they need to be. This solution uses the "android-maps-utils"
// compile 'com.google.maps.android:android-maps-utils:0.3.4'
private ArrayList<Polygon> polygonList = new ArrayList<>();
private void addMyPolygons() {
PolygonOptions options = new PolygonOptions();
// TODO: make your polygon's however you want
Polygon polygon = googleMap.addPolygon(options);
polygonList.add(polygon);
}
#Override
public void onMapClick(LatLng point) {
boolean contains = false;
for (Polygon p : polygonList) {
contains = PolyUtil.containsLocation(point, p.getPoints(), false);
if (contains) break;
}
Toast.makeText(getActivity(), "Click in polygon? "
+ contains, Toast.LENGTH_SHORT).show();
}
#Override
protected void onMapReady(View view, Bundle savedInstanceState) {
googleMap.setOnMapClickListener(this);
addMyPolygons();
}
I know I am posting this very late but I had some issue with the answer posted here, so I studied both the top answers and an article (which I think is the origin of this method) and modified Matt Answer to compile something that works best for me.
Problem with Matt Answer: It doesn't calculate the last line of polygon (i.e. one created by the last vertex and the first vertex)
Problem with Dwill Answer: It seems complex and daunting especially when you are already frustrated on how to make things work
Other checks I have added:
Checked if a polygon is actually created
Checked if any side of polygon is parallel to y-axis
I have tried to comment and explain as much I as I could hope this would be helpful for someone
One more thing, this is written in Dart and mainly focused on finding if current position is inside a geofence.
Future<bool> checkIfLocationIsInsideBoundary({
required LatLng positionToCheck,
required List<LatLng> boundaryVertices,
}) async {
// If there are less than 3 points then there will be no polygon
if (boundaryVertices.length < 3) return false;
int intersectCount = 0;
// Check Ray-cast for lines created by all the vertices in our List
for (int j = 0; j < boundaryVertices.length - 1; j++) {
if (_rayCastIntersect(
positionToCheck,
boundaryVertices[j],
boundaryVertices[j + 1],
)) {
intersectCount++;
}
}
// Check for line created by the last vertex and the first vertex of the List
if (_rayCastIntersect(
positionToCheck,
boundaryVertices.last,
boundaryVertices.first,
)) {
intersectCount++;
}
// If our point is inside the polygon they will always intersect odd number of
// times, else they will intersect even number of times
return (intersectCount % 2) == 1; // odd = inside, even = outside
}
bool _rayCastIntersect(LatLng point, LatLng vertA, LatLng vertB) {
final double aY = vertA.latitude;
final double bY = vertB.latitude;
final double aX = vertA.longitude;
final double bX = vertB.longitude;
final double pY = point.latitude;
final double pX = point.longitude;
// If vertices A and B are both above our point P then obviously the line made
// by A and B cannot intersect with ray-cast of P. Note: Only y-coordinates of
// each points can be used to check this.
if (aY > pY && bY > pY) return false;
// If vertices A and B are both below our point P then obviously the line made
// by A and B cannot intersect with ray-cast of P. Note: Only y-coordinates of
// each points can be used to check this.
if (aY < pY && bY < pY) return false;
// Since we will be casting ray on east side from our point P, at least one of
// the vertex (either A or B) must be east of P else line made by A nd B
// cannot intersect with ray-cast of P. Note: Only x-coordinates of each
// points can be used to check this.
if (aY < pY && bY < pY) return false;
// If line made by vertices is parallel to Y-axis then we will get
// 'Divided by zero` exception when calculating slope. In such case we can
// only check if the line is on the east or the west relative to our point. If
// it is on the east we count is as intersection. Note: we can be sure our
// ray-cast will intersect the line because it is a vertical line, our
// ray-cast is horizontal and finally we already made sure that both the
// vertices are neither above nor below our point. Finally, since `aX == bX`
// we can check if either aX or bX is on the right/east of pX
if (aX == bX) return aX > pX;
// Calculate slope of the line `m` made by vertices A and B using the formula
// `m = (y2-y1) / (x2-x1)`
final double m = (aY - bY) / (aX - bX); // Rise over run
// Calculate the value of y-intersect `b` using the equation of line
final double b = aY - (aX * m); // y = mx + b => b = y - mx
// Now we translate our point P along X-axis such that it intersects our line.
// This means we can pluck y-coordinate of our point P into the equation of
// our line and calculate a new x-coordinate
final double x = (pY - b) / m; // y = mx + b => x = (y - b) / m
// Till now we have only calculated this new translated point but we don't
// know if this point was translated towards west(left) of towards
// east(right). This can be determined in the same way as we have done above,
// if the x-coordinate of this new point is greater than x-coordinate of our
// original point then it has shifted east, which means it has intersected our
// line
return x > pX;
}
Just for consistency - onMapClick is not called when user taps on a polygon (or other overlay), and it's mentioned in javadoc.
I made a workaround to intercept taps events before MapFragment handles them, and project point to map coordinates and check if the point is inside any polygon, as suggested in other answer.
See more details here
with my standard setup of Google Map API v2 it seems to be allowed to scroll outside the existing map data. There is actually a limit for scrolling, but it seems to be quite a bit outside the actual map bounds.
Is there an easy way of fixing this?
In my project, I use function which is called from onCameraChange. It moves the camera back to inside the allowed area of the map.
// First set the bounds
private static final LatLng NORTHEAST = new LatLng("LAT HERE", "LNG HERE");
private static final LatLng SOUTHWEST = new LatLng("LAT HERE", "LNG HERE");
private static final LatLngBounds BOUNDS = new LatLngBounds(SOUTHWEST, NORTHEAST);
The method looks like this:
if (BOUNDS.contains(googleMap.getCameraPosition().target)) {
return;
}
double x = googleMap.getCameraPosition().target.longitude;
double y = googleMap.getCameraPosition().target.latitude;
double maxX = BOUNDS.northeast.longitude;
double maxY = BOUNDS.northeast.latitude;
double minX = BOUNDS.southwest.longitude;
double minY = BOUNDS.southwest.latitude;
if (x < minX) {
x = minX;
}
if (x > maxX) {
x = maxX;
}
if (y < minY) {
y = minY;
}
if (y > maxY) {
y = maxY;
}
googleMap.moveCamera(CameraUpdateFactory.newLatLng(new LatLng(y, x)));
I hope this is what you are looking for.