Android Geofencing (Polygon) - android

How to create Polygon Geofence from multiple geo locations(long,lat values) . Also how to track user is entering into this geofence region or exiting from this region on android.

A geofence is simply an array of lat/long points that form a polygon. Once you have a list of lat/long points, you can use a point-inside-polygon check to see if a location is within the polygon.
This is code I have used in my own projects to perform point-in-polygon checks for very large concave polygons (20K+ vertices):
public class PolygonTest
{
class LatLng
{
double Latitude;
double Longitude;
LatLng(double lat, double lon)
{
Latitude = lat;
Longitude = lon;
}
}
bool PointIsInRegion(double x, double y, LatLng[] thePath)
{
int crossings = 0;
LatLng point = new LatLng (x, y);
int count = thePath.length;
// for each edge
for (var i=0; i < count; i++)
{
var a = thePath [i];
var j = i + 1;
if (j >= count)
{
j = 0;
}
var b = thePath [j];
if (RayCrossesSegment(point, a, b))
{
crossings++;
}
}
// odd number of crossings?
return (crossings % 2 == 1);
}
bool RayCrossesSegment(LatLng point, LatLng a, LatLng b)
{
var px = point.Longitude;
var py = point.Latitude;
var ax = a.Longitude;
var ay = a.Latitude;
var bx = b.Longitude;
var by = b.Latitude;
if (ay > by)
{
ax = b.Longitude;
ay = b.Latitude;
bx = a.Longitude;
by = a.Latitude;
}
// alter longitude to cater for 180 degree crossings
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;
var red = (ax != bx) ? ((by - ay) / (bx - ax)) : float.MAX_VALUE;
var blue = (ax != px) ? ((py - ay) / (px - ax)) : float.MAX_VALUE;
return (blue >= red);
}
}
In terms of program flow, you will want a background service to do location updates and then perform this check against your lat/long polygon data to see if the location is inside.

In case people are still looking for a Polygon Geofencing check, you can complete this with the GoogleMaps.Util.PolyUtil containsLocation method.

Related

How to move latitude and longitude coordinates using a virtual joystick?

I have an 8 directional joystick (consisting of a knob and pad),
after setting an onTouchListener to the pad, in MotionEvent.ACTION_MOVE, I'm calculating position_x, position_y, distance, and angle, to get a direction[1-8]. Given a direction[1-8], I'd like to continuously execute a specific movement(); but MotionEvent.ACTION_MOVE only executes while finger is moving..
How can I execute a movement of the lat lng continuously?
--Lat/Lng Movement (d=direction)--
private void movement(int d, double lat, double lng) {
if (d==1) { //up
lat = lat + 0.0000002;}
else if (d==2){ //upright
lat = lat + 0.0000001;
lng = lng + 0.0000001;
}
else if (d==3) { //right
lng = lng + 0.0000002;
}
else if (d==4) { //downright
lng = lng + 0.0000001;
lat = lat - 0.0000001;
}
else if (d==5) { //down
lat = lat - 0.0000002;
}
else if (d==6) { //downleft
lat = lat - 0.0000001;
lng = lng - 0.0000001;
}
else if (d==7) { //left
lng = lng - 0.0000002;
}
else if (d==8) { //upleft
lat = lat + 0.0000001;
lng = lng - 0.0000001;
}
}
--action_move, getangle, direction--
case MotionEvent.ACTION_MOVE: {
position_x = (int) (pad.getX() + pad.getWidth() / 2 - knob.getWidth() / 2 * -1 - knob.getX() - pad.getPivotX());
position_y = (int) (pad.getY() + pad.getHeight() / 2 - knob.getHeight() / 2 * -1 - knob.getY() - pad.getPivotY());
distance = (float) Math.sqrt(Math.pow(position_x, 2) + Math.pow(position_y, 2));
angle = (float) getangle(position_x, position_y);
knob.setX(event.getX() + pad.getX() - knob.getWidth() / 2);
knob.setY(event.getY() + pad.getY() - knob.getHeight() / 2);
direction();
movement(direction(), lat, lng);
private double getangle(float x, float y) {
if (x >= 0 && y >= 0) return Math.toDegrees(Math.atan(y / x));
else if (x < 0 && y >= 0) return Math.toDegrees(Math.atan(y / x)) + 180;
else if (x < 0 && y < 0) return Math.toDegrees(Math.atan(y / x)) + 180;
else if (x >= 0 && y < 0) return Math.toDegrees(Math.atan(y / x)) + 360;
return 0;
}
private int direction() {
if (distance > 50) {
if (angle >= 67.5 && angle < 112.5) return 1;
else if (angle >= 112.5 && angle < 157.5) return 2;
else if (angle >= 157.5 && angle < 202.5) return 3;
else if (angle >= 202.5 && angle < 247.5) return 4;
else if (angle >= 247.5 && angle < 292.5) return 5;
else if (angle >= 292.5 && angle < 337.5) return 6;
else if (angle >= 337.5 || angle < 22.5) return 7;
else if (angle >= 22.5 && angle < 67.5) return 8;
} else if (distance <= 50) { //knob at rest in middle
return 0;
}
return 0;
}
You can check the following question's top answer and apply the same logic of using threads and have a while loop in your ui thread.
Continuous "Action_DOWN" in Android

check if Latlng is inside polygon

I'm drawing Polygon on city in order to check if current position is inside this polygon or not, and i'm doing that with below code:-
ArrayList<LatLng> polyLoc = new ArrayList<LatLng>();
polyLoc.add(new LatLng(24.643932, 46.297718));
polyLoc.add(new LatLng(24.695098, 46.555897));
polyLoc.add(new LatLng(24.921971, 46.476246));
polyLoc.add(new LatLng(25.147185, 46.366383));
polyLoc.add(new LatLng(25.155886, 47.249409));
polyLoc.add(new LatLng(24.929444, 47.346913));
polyLoc.add(new LatLng(24.691355, 47.106587));
polyLoc.add(new LatLng(24.449060, 47.219197));
polyLoc.add(new LatLng(24.293947, 46.973377));
polyLoc.add(new LatLng(24.641436, 46.299092));
And i checking if the current position is inside this polygon or not by this way :-
if (hasPermission() && gpsTracker.canGetLocation()) {
if (isPointInPolygon(new LatLng(gpsTracker.getLatitude(), gpsTracker.getLongitude()), polyLoc)) {
cash.setVisibility(View.VISIBLE);
cashIcon.setVisibility(View.VISIBLE);
} else {
cash.setVisibility(View.GONE);
cashIcon.setVisibility(View.GONE);
}
Log.d(TAG, "reservationDialog: " + gpsTracker.getLatitude() + gpsTracker.getLongitude());
}
here is my isPointInPolygon method :
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 don't know why it's not working, what i'v missed here?
I don't know why your code didn't work.
But you can use PolyUtil.containsLocation (new LatLng (latitude, longitude), polyLoc, true)
This would return false if the position outside the polygon.
In my project, I'm doing this calculation on the server. I'm using geolib library to do this. If you need to calculate in your app. You can get the logic from the library.
Library:
https://www.npmjs.com/package/geolib
Git: https://github.com/manuelbieh/Geolib

Maps, test if current location is on or near polyline

I'm using google directions api to draw a polyline for a route. Does anyone have any examples of checking if current location is on/near a polyline? Trying to determine if users current location is within x meters of that line and if not i'll make a new request and redraw a new route.
Cheers!
Here is my solution: just add the bdccGeoDistanceAlgorithm class I have created to your project and use bdccGeoDistanceCheckWithRadius method to check if your current location is on or near polyline (polyline equals to a list of LatLng of points)
Your can also get the distance from the method
Class bdccGeoDistanceAlgorithm
import com.google.android.gms.maps.model.LatLng;
import java.util.List;
public class bdccGeoDistanceAlgorithm {
// distance in meters from GLatLng point to GPolyline or GPolygon poly
public static boolean bdccGeoDistanceCheckWithRadius(List<LatLng> poly, LatLng point, int radius)
{
int i;
bdccGeo p = new bdccGeo(point.latitude,point.longitude);
for(i=0; i < (poly.size()-1) ; i++)
{
LatLng p1 = poly.get(i);
bdccGeo l1 = new bdccGeo(p1.latitude,p1.longitude);
LatLng p2 = poly.get(i+1);
bdccGeo l2 = new bdccGeo(p2.latitude,p2.longitude);
double distance = p.function_distanceToLineSegMtrs(l1, l2);
if(distance < radius)
return true;
}
return false;
}
// object
public static class bdccGeo
{
public double lat;
public double lng;
public double x;
public double y;
public double z;
public bdccGeo(double lat, double lon) {
this.lat = lat;
this.lng = lng;
double theta = (lon * Math.PI / 180.0);
double rlat = function_bdccGeoGeocentricLatitude(lat * Math.PI / 180.0);
double c = Math.cos(rlat);
this.x = c * Math.cos(theta);
this.y = c * Math.sin(theta);
this.z = Math.sin(rlat);
}
//returns in meters the minimum of the perpendicular distance of this point from the line segment geo1-geo2
//and the distance from this point to the line segment ends in geo1 and geo2
public double function_distanceToLineSegMtrs(bdccGeo geo1,bdccGeo geo2)
{
//point on unit sphere above origin and normal to plane of geo1,geo2
//could be either side of the plane
bdccGeo p2 = geo1.function_crossNormalize(geo2);
// intersection of GC normal to geo1/geo2 passing through p with GC geo1/geo2
bdccGeo ip = function_bdccGeoGetIntersection(geo1,geo2,this,p2);
//need to check that ip or its antipode is between p1 and p2
double d = geo1.function_distance(geo2);
double d1p = geo1.function_distance(ip);
double d2p = geo2.function_distance(ip);
//window.status = d + ", " + d1p + ", " + d2p;
if ((d >= d1p) && (d >= d2p))
return function_bdccGeoRadiansToMeters(this.function_distance(ip));
else
{
ip = ip.function_antipode();
d1p = geo1.function_distance(ip);
d2p = geo2.function_distance(ip);
}
if ((d >= d1p) && (d >= d2p))
return function_bdccGeoRadiansToMeters(this.function_distance(ip));
else
return function_bdccGeoRadiansToMeters(Math.min(geo1.function_distance(this),geo2.function_distance(this)));
}
// More Maths
public bdccGeo function_crossNormalize(bdccGeo b)
{
double x = (this.y * b.z) - (this.z * b.y);
double y = (this.z * b.x) - (this.x * b.z);
double z = (this.x * b.y) - (this.y * b.x);
double L = Math.sqrt((x * x) + (y * y) + (z * z));
bdccGeo r = new bdccGeo(0,0);
r.x = x / L;
r.y = y / L;
r.z = z / L;
return r;
}
// Returns the two antipodal points of intersection of two great
// circles defined by the arcs geo1 to geo2 and
// geo3 to geo4. Returns a point as a Geo, use .antipode to get the other point
public bdccGeo function_bdccGeoGetIntersection(bdccGeo geo1,bdccGeo geo2, bdccGeo geo3,bdccGeo geo4)
{
bdccGeo geoCross1 = geo1.function_crossNormalize(geo2);
bdccGeo geoCross2 = geo3.function_crossNormalize(geo4);
return geoCross1.function_crossNormalize(geoCross2);
}
public double function_distance(bdccGeo v2)
{
return Math.atan2(v2.function_crossLength(this), v2.function_dot(this));
}
//More Maths
public double function_crossLength(bdccGeo b)
{
double x = (this.y * b.z) - (this.z * b.y);
double y = (this.z * b.x) - (this.x * b.z);
double z = (this.x * b.y) - (this.y * b.x);
return Math.sqrt((x * x) + (y * y) + (z * z));
}
//Maths
public double function_dot(bdccGeo b)
{
return ((this.x * b.x) + (this.y * b.y) + (this.z * b.z));
}
//from Radians to Meters
public double function_bdccGeoRadiansToMeters(double rad)
{
return rad * 6378137.0; // WGS84 Equatorial Radius in Meters
}
// point on opposite side of the world to this point
public bdccGeo function_antipode()
{
return this.function_scale(-1.0);
}
//More Maths
public bdccGeo function_scale(double s)
{
bdccGeo r = new bdccGeo(0,0);
r.x = this.x * s;
r.y = this.y * s;
r.z = this.z * s;
return r;
}
// Convert from geographic to geocentric latitude (radians).
public double function_bdccGeoGeocentricLatitude(double geographicLatitude)
{
double flattening = 1.0 / 298.257223563;//WGS84
double f = (1.0 - flattening) * (1.0 - flattening);
return Math.atan((Math.tan(geographicLatitude) * f));
}
}
}

Find out if a location is within a shape drawn with polygon on Google Maps v2

If I draw a shape with polygon on Google Maps v2, is there a way to find out if my current location is inside the shape?
please write me a clear code thanks
Draw a rectangle on map with points:
List<LatLng> points = new ArrayList<>();
points.add(new LatLng(lat1, lng1));
points.add(new LatLng(lat2, lng2));
points.add(new LatLng(lat3, lng3));
points.add(new LatLng(lat4, lng4));
Polygon polygon = myMap.addPolygon(new PolygonOptions().addAll(points));
Use android-maps-utils library to check to see is polygon contains your current location point:
boolean contain = PolyUtil.containsLocation(currentLocationLatLng, points, true);
You could create a LatLngBounds based on the specifications of your rectangle and then use the contains method to check whether the current location resides within it.
I split the PolyUtil from the Google Maps Android API Utility Library to one class.
Than just call like follow.
ArrayList<LatLng> polygon = new ArrayList<LatLng>();
LatLng myLocation = new LatLng(currentLocation.getLatitude(), currentLocation.getLongitude());
boolean inPolygon = PolyUtil.containsLocation(myLocation, polygon, false);
And include the PolyUtil class in your code.
import static java.lang.Math.PI;
import static java.lang.Math.log;
import static java.lang.Math.sin;
import static java.lang.Math.tan;
import static java.lang.Math.toRadians;
public class PolyUtil {
/**
* 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);
}
/**
* 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;
}
/**
* 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;
}
public static boolean containsLocation(LatLng point, List<LatLng> polygon, boolean geodesic) {
return containsLocation(point.latitude, point.longitude, polygon, geodesic);
}
/**
* 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.
*/
public static boolean containsLocation(double latitude, double longitude, List<LatLng> polygon, boolean geodesic) {
final int size = polygon.size();
if (size == 0) {
return false;
}
double lat3 = toRadians(latitude);
double lng3 = toRadians(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;
}
/**
* 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);
}
}
Follow these -
https://developer.android.com/training/location/geofencing.html
https://developers.google.com/android/reference/com/google/android/gms/location/Geofence
These links may be what you are looking for.
Just tried Ray Casting algorithm which identifies point in polygon. This works perfect.
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;
}

MKCoordinateRegionMakeWithDistance equivalent in Android

We can set the surrounding area for particular location on map in iPhone as following
CLLocationCoordinate2D coord = {latitude:37.09024, longitude:-95.712891};
CLLocationDistance latitudinalMeters;
latitudinalMeters =NoOfMiles * 1609.344;
CLLocationDistance longitudinalMeters;
longitudinalMeters = NoOfMiles * 1609.344;
mapViewHome.region = MKCoordinateRegionMakeWithDistance(coord, latitudinalMeters, longitudinalMeters);
Is there any equivalent method for Android?
This code is not production quality. Use Chris suggestion from comments here instead: https://issuetracker.google.com/issues/35823607#comment4
This question was originally asked for Maps API v1. This answer is for v2, but can be easily changed to v1, so...
No easy way to do it.
You may want to request this feature on gmaps-api-issues.
As waiting for this to be implemented on Google side can take several months, so this is what I would do:
private static final double ASSUMED_INIT_LATLNG_DIFF = 1.0;
private static final float ACCURACY = 0.01f;
public static LatLngBounds boundsWithCenterAndLatLngDistance(LatLng center, float latDistanceInMeters, float lngDistanceInMeters) {
latDistanceInMeters /= 2;
lngDistanceInMeters /= 2;
LatLngBounds.Builder builder = LatLngBounds.builder();
float[] distance = new float[1];
{
boolean foundMax = false;
double foundMinLngDiff = 0;
double assumedLngDiff = ASSUMED_INIT_LATLNG_DIFF;
do {
Location.distanceBetween(center.latitude, center.longitude, center.latitude, center.longitude + assumedLngDiff, distance);
float distanceDiff = distance[0] - lngDistanceInMeters;
if (distanceDiff < 0) {
if (!foundMax) {
foundMinLngDiff = assumedLngDiff;
assumedLngDiff *= 2;
} else {
double tmp = assumedLngDiff;
assumedLngDiff += (assumedLngDiff - foundMinLngDiff) / 2;
foundMinLngDiff = tmp;
}
} else {
assumedLngDiff -= (assumedLngDiff - foundMinLngDiff) / 2;
foundMax = true;
}
} while (Math.abs(distance[0] - lngDistanceInMeters) > lngDistanceInMeters * ACCURACY);
LatLng east = new LatLng(center.latitude, center.longitude + assumedLngDiff);
builder.include(east);
LatLng west = new LatLng(center.latitude, center.longitude - assumedLngDiff);
builder.include(west);
}
{
boolean foundMax = false;
double foundMinLatDiff = 0;
double assumedLatDiffNorth = ASSUMED_INIT_LATLNG_DIFF;
do {
Location.distanceBetween(center.latitude, center.longitude, center.latitude + assumedLatDiffNorth, center.longitude, distance);
float distanceDiff = distance[0] - latDistanceInMeters;
if (distanceDiff < 0) {
if (!foundMax) {
foundMinLatDiff = assumedLatDiffNorth;
assumedLatDiffNorth *= 2;
} else {
double tmp = assumedLatDiffNorth;
assumedLatDiffNorth += (assumedLatDiffNorth - foundMinLatDiff) / 2;
foundMinLatDiff = tmp;
}
} else {
assumedLatDiffNorth -= (assumedLatDiffNorth - foundMinLatDiff) / 2;
foundMax = true;
}
} while (Math.abs(distance[0] - latDistanceInMeters) > latDistanceInMeters * ACCURACY);
LatLng north = new LatLng(center.latitude + assumedLatDiffNorth, center.longitude);
builder.include(north);
}
{
boolean foundMax = false;
double foundMinLatDiff = 0;
double assumedLatDiffSouth = ASSUMED_INIT_LATLNG_DIFF;
do {
Location.distanceBetween(center.latitude, center.longitude, center.latitude - assumedLatDiffSouth, center.longitude, distance);
float distanceDiff = distance[0] - latDistanceInMeters;
if (distanceDiff < 0) {
if (!foundMax) {
foundMinLatDiff = assumedLatDiffSouth;
assumedLatDiffSouth *= 2;
} else {
double tmp = assumedLatDiffSouth;
assumedLatDiffSouth += (assumedLatDiffSouth - foundMinLatDiff) / 2;
foundMinLatDiff = tmp;
}
} else {
assumedLatDiffSouth -= (assumedLatDiffSouth - foundMinLatDiff) / 2;
foundMax = true;
}
} while (Math.abs(distance[0] - latDistanceInMeters) > latDistanceInMeters * ACCURACY);
LatLng south = new LatLng(center.latitude - assumedLatDiffSouth, center.longitude);
builder.include(south);
}
return builder.build();
}
Usage:
LatLngBounds bounds = AndroidMapsExtensionsUtils.boundsWithCenterAndLatLngDistance(new LatLng(51.0, 19.0), 1000, 2000);
map.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0));
Notes:
this code has not been fully tested, may not work for edge cases
you may want to adjust private constants to have it execute faster
you may remove 3rd part where LatLng south is calculated and do it like for longitudes: this will be accurate for small values of latDistance (guessing you will not see a difference under 100km)
code is ugly, so feel free to refactor
While the above answer might work, it does not really look straight forward as the author already mentioned. Here is some code that works for me. Please note the code assumes the earth is a perfect sphere.
double latspan = (latMeters/111325);
double longspan = (longMeters/111325)*(1/ Math.cos(Math.toRadians(location.latitude)));
LatLngBounds bounds = new LatLngBounds(
new LatLng(location.latitude-latspan, location.longitude-longspan),
new LatLng(location.latitude+latspan, location.longitude+longspan));

Categories

Resources