I am drawing the circle on map with specifying the radius and it'll draw the circle successfully. But when I change the size of circle using seekbar I need to feet the circle in screen and zoom the map of that level, I have not idea about this, need your guideline thank you.
We can also get the zoom level for map from the drawn circle
Circle circle = googleMap.addCircle(circleOptions);
googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(
circleOptions.getCenter(), getZoomLevel(circle)
// Methode for zoomlevel
public int getZoomLevel(Circle circle) {
int zoomLevel = 11;
if (circle != null) {
double radius = circle.getRadius() + circle.getRadius() / 2;
double scale = radius / 500;
zoomLevel = (int) (16 - Math.log(scale) / Math.log(2));
}
return zoomLevel;
}
build.gradle:
dependencies {
compile 'com.google.maps.android:android-maps-utils:0.4+'
}
public static LatLngBounds getLatLngBoundsFromCircle(Circle circle){
if(circle != null){
return new LatLngBounds.Builder()
.include(SphericalUtil.computeOffset(circle.getCenter(), circle.getRadius() * Math.sqrt(2), 45))
.include(SphericalUtil.computeOffset(circle.getCenter(), circle.getRadius() * Math.sqrt(2), 225))
.build();
}
return null;
}
map.animateCamera( CameraUpdateFactory
.newLatLngBounds(MapUtils.getLatLngBoundsFromCircle(mapCircle),20) );
After long time I found the solution from somewhere.
here is the method which was giving me the min lat/lng and max lat/lng.
Based on this I have getting the latspan and longspan.
public void boundingCoordinates(double distance, double radius) {
if (radius < 0d || distance < 0d)
throw new IllegalArgumentException();
// angular distance in radians on a great circle
double radDist = distance / radius;
double radLat = Math.toRadians(gp.getLatitudeE6()/1e6); // here is your single point latitude gp.getLatitude
double radLon = Math.toRadians(gp.getLongitudeE6()/1e6); // here is your single point longitude gp.getlongitude
double minLat = radLat - radDist;
double maxLat = radLat + radDist;
double minLon, maxLon;
if (minLat > MIN_LAT && maxLat < MAX_LAT) {
double deltaLon = Math.asin(Math.sin(radDist) /Math.cos(radLat));
minLon = radLon - deltaLon;
if (minLon < MIN_LON)
minLon += 2d * Math.PI;
maxLon = radLon + deltaLon;
if (maxLon > MAX_LON)
maxLon -= 2d * Math.PI;
} else {
// a pole is within the distance
minLat = Math.max(minLat, MIN_LAT);
maxLat = Math.min(maxLat, MAX_LAT);
minLon = MIN_LON;
maxLon = MAX_LON;
}
minLat = Math.toDegrees(minLat);
minLon = Math.toDegrees(minLon);
maxLat = Math.toDegrees(maxLat);
maxLon = Math.toDegrees(maxLon);
minGeo = new GeoPoint((int)(minLat*1e6),(int)(minLon*1e6));
maxGeo = new GeoPoint((int)(maxLat*1e6),(int)(maxLon*1e6));
}
now you pass the distance in any unit as per that you have to pass the radius of earth for example if you pass 2 km then the radius of earth is in km say 6370.997.
you can try it, its cool thing
In my code I am adding a transparent circle around a marker which has dynamic radius and zooming the map camera so it fit to screen.
it is working 100% fine in my project.
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
mMap.setOnMarkerClickListener(this);
MapsInitializer.initialize(Objects.requireNonNull(getContext()));
// Add a marker on Property location
LatLng propertyLatlng = new LatLng(getLatitude(), getLongitude());
// draw transparent blue circle around marker
try {
CircleOptions circleOptions = new CircleOptions()
.center(propertyLatlng)
.radius(Double.parseDouble(radius) / 0.00062137)
.strokeColor(BLUE_TRANSPARENT)
.strokeWidth(0)
.fillColor(BLUE_TRANSPARENT);
Circle circle = mMap.addCircle(circleOptions);
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(
circleOptions.getCenter(), getZoomLevel(circle)));
} catch (Exception e) {
AppLogger.logError(TAG, e.getMessage());
}
}
/**
* #param circle : circle
* #return : return zoom level according to circle radius
*/
public float getZoomLevel(Circle circle) {
int zoomLevel = 11;
if (circle != null) {
double radius = circle.getRadius() + circle.getRadius() / 2;
double scale = radius / 500;
zoomLevel = (int) (16 - Math.log(scale) / Math.log(2));
}
return zoomLevel+.4f;
}
double getZoomLevel() {
double zoomLevel = 0.0;
double newRadius = radiusOfCircle + radiusOfCircle / 2;
double scale = newRadius / 500;
zoomLevel = (6 - log(scale) / log(2));
return zoomLevel;
}
This worked for me
Thanks to #Anand Tiwari
Related
how to show the mapBox map view in specific range in android just like i need to show only Asia pacific in mapView only ,not display full world in mapView android?
You can manually set the zoom level of the map (radius is the radius of the map in meter):
double radius = 500.0;
Circle circle = map.addCircle(new CircleOptions().center(latLng).radius(radius).strokeColor(Color.RED));
circle.setVisible(false);
int zoomLevel = getZoomLevel(circle);
map.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, zoomLevel));
private int getZoomLevel(Circle circle) {
int zoomLevel = 15;
if (circle != null) {
double radius = circle.getRadius();
double scale = radius / 500;
zoomLevel = (int) (16 - Math.log(scale) / Math.log(2));
}
return zoomLevel;
}
I have a set of points coming from a webservice that need to be displayed on a map.
I have a current solution working nicely for most cases, using the well-known LatLngBounds.Builder, CameraUpdateFactory.newLatLngBounds and map.animateCamera.
I have some cases which give problems though: when the points are too far away, the map centers on max zoom level on the barycenter of those points. For example: I have 10 points in France and 2 points in Hawai. Maps centers more or less on the caribeans at min zoom level. Hence on screen I got nothing shown, the user has to scroll to actually see something is there.
So my question is:
is there a way to get the map to zoom out far enough so that I can see all points (that would be prefered)
Or: which would be the best way to filter out those cases where just a few points are very far away from the majority and pick a set of point to zoom on (in my example, I would choose to zoom on the 10 points in France and forget about the ones in Hawai).
Put all the LatLng of the markers in the list and pass them to this method and at the last line in the newLatLngBounds(bounds, 50)) the 50 represent the padding between the map edge and the most outer marker in each side
public void centerIncidentRouteOnMap(List<LatLng> copiedPoints) {
double minLat = Integer.MAX_VALUE;
double maxLat = Integer.MIN_VALUE;
double minLon = Integer.MAX_VALUE;
double maxLon = Integer.MIN_VALUE;
for (LatLng point : copiedPoints) {
maxLat = Math.max(point.latitude, maxLat);
minLat = Math.min(point.latitude, minLat);
maxLon = Math.max(point.longitude, maxLon);
minLon = Math.min(point.longitude, minLon);
}
final LatLngBounds bounds = new LatLngBounds.Builder().include(new LatLng(maxLat, maxLon)).include(new LatLng(minLat, minLon)).build();
mapFragment.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 50));
}
Spotted an error in my previous code and decided to sit down and rewrite it.
I have done something similar before where I had ~4500 markers and wanted to select those within a certain distance of a specific location. Took that code and generalized it to be used with any kind of Markers.
The code that I will post below contains two methods that you can use:
selectLowDistanceMarkers
Measures distance between each and every marker and selects only those that does not have a long distance to any of the other markers. This requires a O(n+n^2) runtime due to the comparison between every marker and an examination afterwards.
getSurroundingMarkers
If you already know a postition that you would like to zoom in to, then this method does the same as above. This method is way less CPU heavy as it only has to do a O(n) run through all the markers and compare them to the given position.
private List<Marker> selectLowDistanceMarkers(List<Marker> markers,
int maxDistanceMeters) {
List<Marker> acceptedMarkers = new ArrayList<Marker>();
if (markers == null) return acceptedMarkers;
Map<Marker, Float> longestDist = new HashMap<Marker, Float>();
for (Marker marker1 : markers) {
// in this for loop we remember the max distance for each marker
// think of a map with a flight company's routes from an airport
// these lines is drawn for each airport
// marker1 being the airport and marker2 destinations
for (Marker marker2 : markers) {
if (!marker1.equals(marker2)) {
float distance = distBetween(marker1.getPosition(),
marker2.getPosition());
if (longestDist.containsKey(marker1)) {
// possible we have a longer distance
if (distance > longestDist.get(marker1))
longestDist.put(marker1, distance);
} else {
// first distance
longestDist.put(marker1, distance);
}
}
}
}
// examine the distances collected
for (Marker marker: longestDist.keySet()) {
if (longestDist.get(marker) <= maxDistanceMeters) acceptedMarkers.add(marker);
}
return acceptedMarkers;
}
private List<Marker> getSurroundingMarkers(List<Marker> markers,
LatLng origin, int maxDistanceMeters) {
List<Marker> surroundingMarkers = surroundingMarkers = new ArrayList<Marker>();
if (markers == null) return surroundingMarkers ;
for (Marker marker : markers) {
double dist = distBetween(origin, marker.getPosition());
if (dist < getHydrantsLoadradius()) {
surroundingMarkers.add(marker);
}
}
return surroundingMarkers;
}
private float distBetween(LatLng pos1, LatLng pos2) {
return distBetween(pos1.latitude, pos1.longitude, pos2.latitude,
pos2.longitude);
}
/** distance in meters **/
private float distBetween(double lat1, double lng1, double lat2, double lng2) {
double earthRadius = 3958.75;
double dLat = Math.toRadians(lat2 - lat1);
double dLng = Math.toRadians(lng2 - lng1);
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
+ Math.cos(Math.toRadians(lat1))
* Math.cos(Math.toRadians(lat2)) * Math.sin(dLng / 2)
* Math.sin(dLng / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
double dist = earthRadius * c;
int meterConversion = 1609;
return (float) (dist * meterConversion);
}
Again, use the well known LatLngBounds to determine how much you need to zoom after using one of the filtering algorithms above.
Based on some ideas from cYrixmorten, I have simplified the problem because I know the map can accomodate at least 4000km of surface. So here is the function to build the list of ignored webcams (then I simply ignore that webcam for the camera bounds computation but still add the marker so that it is on the map if the user moves).
private List<Webcam> buildIgnoredWebcamsList(List<Webcam> webcams) {
if (webcams == null || webcams.size() < 2) return Lists.newArrayList();
int webcamCount = webcams.size();
// Number of conflicts (distance > 4000 km) for the camera at index #
float averageConflictCount = 0;
int[] conflictCount = new int[webcamCount];
Arrays.fill(conflictCount, 0);
// Find number of conflicts between camera pairs
float[] distance = new float[1];
for (int i = 0; i < webcamCount - 1; ++i) {
Webcam a = webcams.get(i);
// We don't have to start from 0, compare a and b only once
for (int j = i + 1; j < webcamCount; ++j) {
Webcam b = webcams.get(j);
Location.distanceBetween(a.getLatitude(), a.getLongitude(), b.getLatitude(), b.getLongitude(), distance);
// We have a conflict between a and b if they are more than 4000km away
if (distance[0] > 4000 * 1000) {
conflictCount[i] += 1;
conflictCount[j] += 1;
averageConflictCount += 2;
}
}
}
averageConflictCount /= webcamCount;
// Exclude all webcams with a number of conflicts greater than the average
List<Webcam> ignoredCamerasForBounds = Lists.newArrayList();
for (int i = 0; i < webcamCount; ++i) {
if (conflictCount[i] > averageConflictCount) {
ignoredCamerasForBounds.add(webcams.get(i));
}
}
return ignoredCamerasForBounds;
}
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int ancho = size.x;
int alto =size.y;
List<LatLng> copiedPoints = new ArrayList<LatLng>();
copiedPoints.add(origin);
copiedPoints.add(dest);
centerIncidentRouteOnMap(copiedPoints, ancho, alto);
....
public void centerIncidentRouteOnMap(List<LatLng> copiedPoints, int ancho, int alto) {
double minLat = Integer.MAX_VALUE;
double maxLat = Integer.MIN_VALUE;
double minLon = Integer.MAX_VALUE;
double maxLon = Integer.MIN_VALUE;
for (LatLng point : copiedPoints) {
maxLat = Math.max(point.latitude, maxLat);
minLat = Math.min(point.latitude, minLat);
maxLon = Math.max(point.longitude, maxLon);
minLon = Math.min(point.longitude, minLon);
}
final LatLngBounds bounds = new LatLngBounds.Builder().include(new LatLng(maxLat, maxLon)).include(new LatLng(minLat, minLon)).build();
map.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds,ancho, alto, 50));
}
I am using com.google.android.gms.maps.GoogleMap in SherlockFragmentActivity.
XML code is this :
<fragment
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="fill_parent"
android:layout_height="150dip" />
int zoomLevel = ? // How I can calculate the zoom level for two diffrent latlong values
as android map v3 need to tell zoom level as int
map.setZoom(zoomLevel);
I have start and destination values as com.google.android.gms.maps.model.LatLng
LatLng start , end;
I am adding a pligon like GoogleLocation.addPolyLineOnGMap(mMap, startPoint, endPoint, startMarker, endMarker)
My problem is how I can calculate zoom level for Google map so it can show both marker appropriately on map.
Use LatLngBounds.Builder add all the bounds in it and build it, Then create the CameraUpdate object and pass the bounds in it updatefactory with padding. Use this CameraUpdate object to animate the map camera.
LatLngBounds.Builder builder = new LatLngBounds.Builder();
for (Marker m : markers) {
builder.include(m.getPosition());
}
LatLngBounds bounds = builder.build();
int padding = ((width * 10) / 100); // offset from edges of the map
// in pixels
CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds,
padding);
mMap.animateCamera(cu);
For me, i need to calculate the zoom for initial map setup by GoogleMapOptions, so using LatLngBounds.Builder
would not work and not optimized. This is how I calculate the zoom based on a city's northeast and southwest coordinates
It's referencing here and this answer, you can simply put the code below to your helper class:
final static int GLOBE_WIDTH = 256; // a constant in Google's map projection
final static int ZOOM_MAX = 21;
public static int getBoundsZoomLevel(LatLng northeast,LatLng southwest,
int width, int height) {
double latFraction = (latRad(northeast.latitude) - latRad(southwest.latitude)) / Math.PI;
double lngDiff = northeast.longitude - southwest.longitude;
double lngFraction = ((lngDiff < 0) ? (lngDiff + 360) : lngDiff) / 360;
double latZoom = zoom(height, GLOBE_WIDTH, latFraction);
double lngZoom = zoom(width, GLOBE_WIDTH, lngFraction);
double zoom = Math.min(Math.min(latZoom, lngZoom),ZOOM_MAX);
return (int)(zoom);
}
private static double latRad(double lat) {
double sin = Math.sin(lat * Math.PI / 180);
double radX2 = Math.log((1 + sin) / (1 - sin)) / 2;
return Math.max(Math.min(radX2, Math.PI), -Math.PI) / 2;
}
private static double zoom(double mapPx, double worldPx, double fraction) {
final double LN2 = .693147180559945309417;
return (Math.log(mapPx / worldPx / fraction) / LN2);
}
Creating LatLng simply by new LatLng(lat-double, lng-double)
width and height is the map layout size in pixels
in Android:
LatLngBounds group = new LatLngBounds.Builder()
.include(tokio) // LatLgn object1
.include(sydney) // LatLgn object2
.build();
mMap.animateCamera(CameraUpdateFactory.newLatLngBounds(group, 100)); // Set Padding and that's all!
Is there a way to get the coordinates of the current area, which is shown at the device?
Background is, we want to show "nearby" places, which are stored in our own database. So let's say, the user looks at following clip of a map:
How do we get the longitude/latitude of the screen (or the point in the middle of the screen and a radius which covers everything?). Please keep in mind, center of the map is not usually the current position, since the user can move the center of the card!
Use map.getProjection().getVisibleRegion(). From VisibleRegion you can get LatLngBounds, which is easy to work with. You may also try directly with the region, which might be trapezoid.
I found the solution for Google Map API v2 from few of responses:
stackoverflow#1 and
stackoverflow#2
So, need implements Activity from GoogleMap.OnCameraChangeListener interface
private static final int REQUEST_CODE_GOOGLE_PLAY_SERVECES_ERROR = -1;
private static final double EARTH_RADIOUS = 3958.75; // Earth radius;
private static final int METER_CONVERSION = 1609;
private GoogleMap mGoogleMap;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_layout);
int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(mContext);
if (status != ConnectionResult.SUCCESS)
{
Dialog dialog = GooglePlayServicesUtil.getErrorDialog(status, activity,
REQUEST_CODE_GOOGLE_PLAY_SERVECES_ERROR);
dialog.show();
mGoogleMap = null;
}
else
{
mGoogleMap = ((SupportMapFragment) getFragmentManager().findFragmentById(
R.id.fragment_shops_layout_maps_fragment)).getMap();
mGoogleMap.setOnCameraChangeListener(this);
}
}
The listener, that working when map scaled. Determin as LatLng the positions of bottom left, bottom right, top left and top right sides of map, that showing on screen. By greatest side of screen and two points we can get radius from center of map.
#Override
public void onCameraChange(CameraPosition cameraPosition)
{
// Listener of zooming;
float zoomLevel = cameraPosition.zoom;
VisibleRegion visibleRegion = mGoogleMap.getProjection().getVisibleRegion();
LatLng nearLeft = visibleRegion.nearLeft;
LatLng nearRight = visibleRegion.nearRight;
LatLng farLeft = visibleRegion.farLeft;
LatLng farRight = visibleRegion.farRight;
double dist_w = distanceFrom(nearLeft.latitude, nearLeft.longitude, nearRight.latitude, nearRight.longitude);
double dist_h = distanceFrom(farLeft.latitude, farLeft.longitude, farRight.latitude, farRight.longitude);
Log.d("DISTANCE: ", "DISTANCE WIDTH: " + dist_w + " DISTANCE HEIGHT: " + dist_h);
}
Return distance between 2 points, stored as 2 pair location at meters;
public double distanceFrom(double lat1, double lng1, double lat2, double lng2)
{
// Return distance between 2 points, stored as 2 pair location;
double dLat = Math.toRadians(lat2 - lat1);
double dLng = Math.toRadians(lng2 - lng1);
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(Math.toRadians(lat1))
* Math.cos(Math.toRadians(lat2)) * Math.sin(dLng / 2) * Math.sin(dLng / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
double dist = EARTH_RADIOUS * c;
return new Double(dist * METER_CONVERSION).floatValue();
}
If you want get radius of area, that showed on screen just need devided by 2.
I hope will useful !
This calculates the radio in km based on the map width:
public double calculateVisibleRadius() {
float[] distanceWidth = new float[1];
VisibleRegion visibleRegion = map.getProjection().getVisibleRegion();
LatLng farRight = visibleRegion.farRight;
LatLng farLeft = visibleRegion.farLeft;
LatLng nearRight = visibleRegion.nearRight;
LatLng nearLeft = visibleRegion.nearLeft;
//calculate the distance between left <-> right of map on screen
Location.distanceBetween( (farLeft.latitude + nearLeft.latitude) / 2, farLeft.longitude, (farRight.latitude + nearRight.latitude) / 2, farRight.longitude, distanceWidth );
// visible radius is / 2 and /1000 in Km:
return distanceWidth[0] / 2 / 1000 ;
}
I have a map included in an application. I need the map to zoom in on the a marker and the users location but keep the marker centered. The zoom in works perfectly, but of course doesn't center the marker on the map.
#Override
public void onLocationChanged(Location location) {
if (mListener != null) {
mListener.onLocationChanged(location);
LatLngBounds bounds = new LatLngBounds.Builder()
.include(new LatLng(location.getLatitude(),location.getLongitude()))
.include((new LatLng(52.3563, 4.8790)))
.build();
mMap.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 35));
}
}
What is the best way to keep both within the bounds but keep the marker centered? I can't seem to find a solution in the official documentation.
There are two functions I would call, one for centering the marker and an other one to zoom on the map until your current location is still visible.
My solution for zooming to a point with a 15 zoom level:
myMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLngToCenter, 1));
zooming until all markers are still visible (change code to fit the marker and your position instead):
public void fitZoomAndPositionToMapByMarkers() {
int minLat = Integer.MAX_VALUE;
int maxLat = Integer.MIN_VALUE;
int minLon = Integer.MAX_VALUE;
int maxLon = Integer.MIN_VALUE;
List<MyMapMarker> markersShownOnMap = getMarkersToShow();
for (MyMapMarker item : markersShownOnMap) {
int lat = (int) (item.getLatitude() * 1E6);
int lon = (int) (item.getLongitude() * 1E6);
maxLat = Math.max(lat, maxLat);
minLat = Math.min(lat, minLat);
maxLon = Math.max(lon, maxLon);
minLon = Math.min(lon, minLon);
}
double latitudeToGo = (maxLat + minLat) / 1E6 / 2;
double longitudeToGo = (maxLon + minLon) / 1E6 / 2;
LatLng toCenter = new LatLng(latitudeToGo, longitudeToGo);
centerCameraToProperPosition(toCenter);
LatLng southWestLatLon = new LatLng(minLat / 1E6, minLon / 1E6);
LatLng northEastLatLon = new LatLng(maxLat / 1E6, maxLon / 1E6);
zoomInUntilAllMarkersAreStillVisible(southWestLatLon, northEastLatLon);
}
Hope this helps!
private void zoomInUntilAllMarkersAreStillVisible(final LatLng southWestLatLon, final LatLng northEastLatLon) {
myMap.setOnCameraChangeListener(new OnCameraChangeListener() {
#Override
public void onCameraChange(CameraPosition arg0) {
myMap.moveCamera(CameraUpdateFactory.newLatLngBounds(new LatLngBounds(southWestLatLon, northEastLatLon), 50));
myMap.setOnCameraChangeListener(null);
}
});
}
Hello i have found a nice and easy way using LatLngbounds:
googleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(new LatLngBounds(latlngSW, latlngNE, 50));
this function will use the most SW point and the most NE point to create a rectangle to center the view with 50 padding, but u need to check first which one of the points should be given as first or second parameter, here is my code:
public void centerMap(LatLng latLng){
if(fenceMarker != null){
LatLngBounds center;
LatLng fence = fenceMarker.getPosition();
if(fence.latitude < latLng.latitude || fence.longitude < latLng.longitude)
center = new LatLngBounds(fenceMarker.getPosition(), latLng);
else{
center = new LatLngBounds(latLng, fenceMarker.getPosition());
}
googleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(center, 50));
}
}
The 2 points are my position latLng and the marker I have for the GeoFence, fenceMarker.
I call this function centerMap(latLng) from the onLocationChanged():
#Override
public void onLocationChanged(Location location) {
LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
centerMap(latLng);
}
Setting Boundaries -
An overload of the method, newLatLngBounds(boundary, width, height, padding) allows you to specify a width and height in pixels for a rectangle, with the intention that these correspond to the dimensions of the map. The rectangle is positioned such that its center is the same as that of the map's view (so that if the dimensions specified are the same as those of the map's view, then the rectangle coincides with the map's view). The returned CameraUpdate will move the camera such that the specified LatLngBounds are centered on screen within the given rectangle at the greatest possible zoom level, taking into account the padding required.
Reference- https://developers.google.com/maps/documentation/android/views#target_location