I want to draw a static circle over a map with Google Maps. When the user pinches, the map will zoom in/out.
I need to know the map radius (related to the area contained in the circle) and change the seekbar at the bottom accordingly.
Does anybody know a solution how to retrieve the distance from the left to the right screen edge? I didn't find anything at the Google Maps API doc.
Something like this:
using VisibleRegion you can get the all corner cordinates and also the center.
VisibleRegion vr = mMap.getProjection().getVisibleRegion();
double left = vr.latLngBounds.southwest.longitude;
double top = vr.latLngBounds.northeast.latitude;
double right = vr.latLngBounds.northeast.longitude;
double bottom = vr.latLngBounds.southwest.latitude;
and you can calcuate distance from two region by this
Location MiddleLeftCornerLocation;//(center's latitude,vr.latLngBounds.southwest.longitude)
Location center=new Location("center");
center.setLatitude( vr.latLngBounds.getCenter().latitude);
center.setLongitude( vr.latLngBounds.getCenter().longitude);
float dis = center.distanceTo(MiddleLeftCornerLocation);//calculate distane between middleLeftcorner and center
I got a while to write the code for "MiddleLeftCornerLocation" variable in the great answer given by #Md. Monsur Hossain Tonmoy, so just to complete it (I haven't enough reputation points to comment your answer, sorry):
VisibleRegion vr = map.getProjection().getVisibleRegion();
double bottom = vr.latLngBounds.southwest.latitude;
Location center = new Location("center");
center.setLatitude(vr.latLngBounds.getCenter().latitude);
center.setLongitude(vr.latLngBounds.getCenter().longitude);
Location middleLeftCornerLocation = new Location("center");
middleLeftCornerLocation.setLatitude(center.getLatitude());
middleLeftCornerLocation.setLongitude(left);
float dis = center.distanceTo(middleLeftCornerLocation);
First get the map center point with
googleMap.getCameraPosition().target;
then figure out the width of the map and get the height/2 and convert them to a Point using the x y values you just got.
then relate that point to the map
LatLng widthPoint = map.getProjection().fromScreenLocation(point);
now that you have the tagret point and the width point you can calculate the distance between the 2 points which will give you the radius.
Note
this assumes always in portrait mode, if you are in landscape mode the circle will be bigger than the visible area so in this case you will want to get the distance from the height
Related
I have been searching but I couldn't find it. I am using google map v2. Is there any way I can convert distance ( meters) to pixels on my screen? I need the pixels equivalent of the distance. I have the distance and I have the zoom level.
Any help is appreciated.
If I understand correctly, you have a MapFragment on your screen showing a map. You know the distance in meters between 2 points on the map that are shown on the screen and you want to calculate the distance between those two points in pixels. If you know the LatLng location of the two points, you can use the Projection class like this:
Point point1 = map.getProjection().toScreenLocation(latLng1);
Point point2 = map.getProjection().toScreenLocation(latLng2);
and then you just need to use the distance mathematic formula:
I've looked on the net but couldn't find an accurate answer. I have an ImageView to use as a marker centred on map, Its position not change when I pan the map. I want to get the latlng of position when I stop panning on the map. I guess I have to use projection but because of I am not so expert in android I got stuck. Can anybody help please.
Use map.getProjection().fromScreenLocation(Point) and map.getProjection().toScreenLocation(LatLng) to convert between screen position and geo location.
Use the Projection via map.getProjection().
This will allow you to convert between screen coordinates and LatLngs. The pixels returned are relative to the View containing the map.
For Maps API v2
VisibleRegion vr = mMap.getProjection().getVisibleRegion();
double left = vr.latLngBounds.southwest.longitude;
double top = vr.latLngBounds.northeast.latitude;
double right = vr.latLngBounds.northeast.longitude;
double bottom = vr.latLngBounds.southwest.latitude;
Also you can use,
LatLngBounds curScreen = mMap.getProjection()
.getVisibleRegion().latLngBounds;
Hope this will help.
I believe this is a limitation of the recent Google Maps API v2. They have recently added the ability to draw a Circle on the ground - but if you want to position the camera such that it shows the entire Circle, there exists no way to do so.
One can call CameraUpdateFactory#newLatLngBounds(bounds, padding) where "bounds" is a LatLngBounds and "padding" is a distance in pixels. The issue is that there is no way to create a LatLng and a radius into a LatLngBounds.
The constructor for LatLngBounds only takes 2 LatLng instances and generates a rectangle where these are the NW and SE corners.
Just like Risadinha mentioned, you can easily achieve that with android-maps-utils. Just add:
compile 'com.google.maps.android:android-maps-utils:0.4.4'
to your gradle dependencies, use the following code:
public LatLngBounds toBounds(LatLng center, double radiusInMeters) {
double distanceFromCenterToCorner = radiusInMeters * Math.sqrt(2.0);
LatLng southwestCorner =
SphericalUtil.computeOffset(center, distanceFromCenterToCorner, 225.0);
LatLng northeastCorner =
SphericalUtil.computeOffset(center, distanceFromCenterToCorner, 45.0);
return new LatLngBounds(southwestCorner, northeastCorner);
}
EDIT:
Our goal is to calculate two points (LatLngs):
southwestCorner
and
northeastCorner
From the javadoc of the SphericalUtil you can read that 225 and 45 are heading values, and the distanceFromCenterToCorner is the distance. Further explanation of the values in the picture below:
With the javascript library you can draw a circle with a center and radius and then get its bounds.
centerSfo = new google.maps.LatLng(37.7749295, -122.41941550000001);
circle = new google.maps.Circle({radius: 5000, center: centerSfo});
bounds = circle.getBounds();
You could do the same using the android api.
This is totally doable.
The LatLng is the center of your circle correct? What you want to do is inscribe your circle inside of the LatLngBounds (Circle inside a Square problem), so the entire thing will show up on the map.
If you draw this on paper you can see that you have everything you need to calculate your LatLngBounds.
Remember how to find the lengths of the sides of a right triangle?
a² + b² = c²
If you draw a line from the center of your circle to the NW (upper left) corner, and another straight to the Western wall (straight line from center, to the left) of the square you have a triangle. Now you can use the equation above to solve for c since you know the the length of the other sides of the triangle (the circle's radius).
So now your equation becomes
r² + r² = c²
which reduces to
2r² = c²
which further reduces to
c = squareRoot(2) * r
Now you have the distance. This is of course an oversimplification, because the Earth is not flat. If the distances aren't huge, you could use the same equation above, but modified to project a spherical earth onto a plane:
http://en.wikipedia.org/wiki/Geographical_distance#Flat-surface_formulae
Notice this also uses the Pythagorean theorem, same as we did above.
Next you will need to calculate your endpoints (NW, and SE corners) from your center point given a bearing, and the distance you found above.
This post may help: Calculate endpoint given distance, bearing, starting point
Don't forget to convert your degrees to radians when using the equation from the post linked above! ( Multiply degrees by pi/180 )
There is a utility library by Google for that:
http://googlemaps.github.io/android-maps-utils/
Recommended by Google for this task and example code:
http://code.google.com/p/gmaps-api-issues/issues/detail?id=5704
While Bartek Lipinski's answer is correct if your LatLngBounds define a square, most LatLngBounds define rectangles, and as such, the bearings of the North-East and the South-West points from the center will not always be 45 and 255 degrees.
Therefore if you are looking to get the LatLngBounds of a radius from a center for any quadrilateral, use the coordinates of your initial bounds.northeast and bounds.southwest like this (using SphericalUtils):
LatLng northEast = SphericalUtil.computeOffset(center, radius * Math.sqrt(2.0), SphericalUtil.computeHeading(center, bounds.northeast));
LatLng southWest = SphericalUtil.computeOffset(center, radius * Math.sqrt(2.0), (180 + (180 + SphericalUtil.computeHeading(center, bounds.southwest))));
(180 + (180 + x)) calculates the bearing of the South-West point from the center clockwise.
Hint: Here is a similar post with HTML.
In the current tablet implementation of my app, I have a fullscreen MapView with some informations displayed in a RelativeLayout on a left panel, like this:
(My layout is quite trivial, and I guess there is no need to post it for readability)
The problem comes when I want to center the map on a specific point... If I use this code:
mapController.setCenter(point);
I will of course get the point in the center of the screen and not in the center of the empty area.
I have really no idea where I could start to turn the offset of the left panel into map coordinates...
Thanks a lot for any help or suggestion
You can achive your objective by getting the map coordinates from top-left and bottom-right corners and divide it by the screen size, to get the value per pixel.
Then you just need to multiply by the offset and add it to the original center.
Example code:
private void centerMap(GeoPoint center, int offX, int offY){
GeoPoint tl = mapView.getProjection().fromPixels(0, 0);
GeoPoint br = mapView.getProjection().fromPixels(mapView.getWidth(), mapView.getHeight());
int newLon = offX * (br.getLongitudeE6() - tl.getLongitudeE6()) / mapView.getWidth() + center.getLongitudeE6();
int newLat = offY * (br.getLatitudeE6() - tl.getLatitudeE6()) / mapView.getHeight() + center.getLatitudeE6();
mapController.setCenter(new GeoPoint(newLat, newLon));
}
To use, you call the above method with your original center and both offsets (x and Y) to apply.
Note: as written, the code above move map left for positive offset values, and right for negative offset values. From the screen in your question you will need to use negative offset, to move map left, and a zero offset for Y.
Regards
I have a MapView centered at point P. The user can't change the MapView center, but he can choose a radius of a circle to be display around point P, and change it dynamically with the map being redrawn at each change to show the new circle.
The thing is, i want the map to zoom in or out as necessary, in order to display the entire circle at the viewable area. I've tried this:
Projection proj = m_Map.getProjection();
Point mapCenterPixles = new Point();
proj.toMapPixels(center, mapCenterPixles);
float radiusPixels = proj.metersToEquatorPixels(newRadius);
IGeoPoint topLeft = proj.fromPixels(mapCenterPixles.x - radiusPixels,
mapCenterPixles.y - radiusPixels);
IGeoPoint bottomRight = proj.fromPixels(mapCenterPixles.x
+ radiusPixels, mapCenterPixles.y + radiusPixels);
m_Map.getController().zoomToSpan(
topLeft.getLatitudeE6() - bottomRight.getLatitudeE6(),
topLeft.getLongitudeE6() - bottomRight.getLongitudeE6());
But it seems i'm missing something, as the values passed to zoomToSpan() cause no chnage, I'm kind of lost here, can someone please shed some light on how to zoom the map to span a bounding box of the circle given its radius in meters, and its center points?
Google Maps zoom levels are defined in powers of two, so MapController#zoomToSpan() also zooms by powers of two.
Ergo, if the span you compute above is already displayable within the current zoom level, it's likely nothing would actually change visually in the map until you need to go to the next larger or smaller zoom level.
This behavior is somewhat vaguely described in the documentation for MapController#zoomToSpan