Android: MapView.GetLatitudeSpan(), GetLongitudeSpan() Anomaly? - android

I'm working on a mapping app that plots pins on a MapView based on a user's query. I'm trying to scale the map to fit all the results pins, but I've run into a seemingly strange situation.
I have two variables set up:
latSpan is the difference between the maximum latitude and minimum latitude of any of the results points
lonSpan is the difference between the maximum longitude and minimum longitude of any of the results points
This method
while ((mapView.getLatitudeSpan()) < latSpan) || (mapView.getLongitudeSpan() < lonSpan)){
mapController.zoomOut();
}//end of while loop
is supposed to zoom out to make sure all the pins fit on the viewable map screen.
But I'm experiencing something rather strange. The results of mapView.getLatitudeSpan() and mapView.getLongitudeSpan() are routinely greater than my latSpan and lonSpan values, so the MapController doesn't zoom out enough.
My map is zoomed in pretty far--level 15 or higher.
As an example, one set of search results gave the following values:
latSpan = 17928
lonSpan = 11636
mapView.getLatitudeSpan() = 21933
mapView.getLongitudeSpan() = 20598
Based on these numbers, you wouldn't think that the MapController would need to zoom out. Yet there are pins plotted both above the top and below the bottom of the screen. I changed my WHILE loop to read
while ((mapView.getLatitudeSpan() - 6000) < latSpan...
and that helps, but the right query will still cause issues.
But the real question is, why is this happening?

I'm not sure why you're code isn't working from the snippet provided. Its possible that you are not converting your latSpan and lonSpan to microDegrees (as shown below) and this would cause some issues.
Also if you're trying to make sure your mapView is showing all of the results, there's not much point trying to determine if it needs to zoom before zooming, just zoom it every time. If it turns out that it doesn't need to zoom then nothing will appear to happen and if it does then it does.
You can set a map up to encompass all of your points and move to the centroid of the points as follows:
GeoPoint max = new GeoPoint(maxLatitude, maxLongitude);
GeoPoint min = new GeoPoint(minLatitude, minLongitude);
int maxLatMicro = max.getLatitudeE6();
int maxLonMicro = max.getLongitudeE6();
int minLatMicro = min.getLatitudeE6();
int minLonMicro = min.getLongitudeE6();
GeoPoint center = new GeoPoint((maxLatMicro+minLatMicro)/2,(maxLonMicro + minLonMicro)/2);
controller.zoomToSpan(maxLatMicro - minLatMicro, maxLonMicro - minLonMicro);
controller.animateTo(center);

Related

Android compute right bbox for WMS getFeatureInfo

I'm trying to make a request to my Geoserver to retrieve the features near the tap of a user on the map.
The map takes all the space. Therefore I computed the BBOX in this way:
region = mMap.getProjection().getVisibleRegion().latLngBounds;
double left = region.southwest.longitude;
double top = region.northeast.latitude;
double right = region.northeast.longitude;
double bottom = region.southwest.latitude;
and the width and height are taken as belows:
mMapFragment.getView().getWidth();
mMapFragment.getView().getHeight();
while the X and Y parameter are calculated in the following way:
Point click = mMap.getProjection().toScreenLocation(latLng);
where latLng is the point that came from the event onMapClick(LatLng) (reference here: https://developers.google.com/android/reference/com/google/android/gms/maps/GoogleMap.OnMapClickListener).
The resulting URL that I obtain is:
http://localhost/geoserver/sindot/wms?service=WMS&request=GetFeatureInfo&info_format=application%2Fjson&version=1.1.1&srs=EPSG%3A3857&bbox=1222173.74033,5056403.44084,1222174.11356,5056403.7028&query_layers=sindot:verticale&layers=sindot:verticale&feature_count=3&styles=tabletb3lab&width=2048&height=1262&x=1441&y=503
The problem is that the server returns always an empty response even if I know that there are features there because I can see the spots on the map. What could it be?
Thanks in advance.
It onlytook to add &buffer=10 (or another number according to your needs) to the request.

Touch detection on polyline in Google Maps Android API v2

I want to implement a touchListener on a polyline displayed with Google Maps V2 Android API.
Zoom level:
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(lat_Lng, 5);
I tried the following polyline touch code:
boolean onpoly = false;
for (Polyline polyline : mPolylines) {
for (LatLng polyCoords : polyline.getPoints()) {
float[] results = new float[1];
Location.distanceBetween(points.latitude, points.longitude, polyCoords.latitude, polyCoords.longitude, results);
if (results[0] < 100 ) {
onpoly = true;
Marker mark = map.addMarker(new MarkerOptions().position(points).title("AddEvent")
.snippet("" + addressaddexpense).icon(BitmapDescriptorFactory.fromResource(R.drawable.addicon)));
UtilsClass.dropPinEffect(mark);
}// end if..
} // end for loop
}// end for loop
if (onpoly == true) {
Toast.makeText(getActivity(), "Poly line detected", Toast.LENGTH_SHORT).show();
}// end if
It worked but not perfectly.
it will not detect the touch event unless i zoom in, sometimes forcing me to tap the map more than 5 times before zooming to achieve detection.
I then changed the aforementioned if condition from if (results[0] < 100 ) to if (results[0] < 150 * (22 - map.getCameraPosition().zoom)) and the functionality improved but it still does not work all the time.
Note: I want to detect polyline touch at any zoom level.
try this
final List<LatLng> latLngList; // Extract polyline coordinates and put them on this list
private GoogleMap map;
for(int i = 0; i < latLngList.size(); i++){
MarkerOptions mar = new MarkerOptions();
mar.position(new LatLng(latLngList.get(i).latitude, latLngList.get(i).longitude)).icon(BitmapDescriptorFactory.fromResource(R.drawable.trasparent_image)); //this image should be very small in size and transparent
map.addMarker(mar);
}
map.setOnMarkerClickListener(new OnMarkerClickListener() {
#Override
public boolean onMarkerClick(Marker arg0) {
for(int i = 0; i < latLngList.size(); i++){
if(latLngList.get(i).latitude == arg0.getPosition().latitude && latLngList.get(i).longitude == arg0.getPosition().longitude){
Toast.makeText(MainActivity.this, "PolyLineClick ", Toast.LENGTH_SHORT).show();
break;
}
}
return false;
}
});
Until the questions in my comments are answered i thought i'll try to make them redundant by suggesting the usage of a 3rd party library; android-maps-utils
To do what i think you might be trying to do simply integrate the library and use the following line:
PolyUtil.isLocationOnPath(point, polyline.getPoints(), isGeodesic, tolerance);
For more information you can also look into this thread which seems applicable.
Goodluck.
I think your approach is correct. The only thing that fails is the distance check. And this is because os the touch and the zoom level:
You know that when you tap on the screen, the screen point that is passed to the applications is the center of your finger surface, that is in touch with the screen. This means, that even if it seems, that your finger is exactly over the PolyLine, it can be displaced with some pixels...
Now is time for the Zoom level, and depending in its current value, the distance between the point passed to the application and the PolyLine, can vary very much.
As a result, the if clause fails, and you have to tap several times, until some of your taps is near enough to the PolyLine. And of course it gets better with higher zoom level.
You should include the zoom level as you have done in you edited code, but with some extras: Check the "delta" that you will allow to enter the if, but on the max zoom level. It should be a small value. Then you have to just multiply it by the current zoom level, and calculate how this delta changes. Use this zoom dependant value in your if comparison.To enhance it, you can make a more complex calculation and get this delta, starting from pixel distance. Lets say, a tap that at 50px or less to the PolyLine will be accepted. Calculate this pixel distance in meters, again on the max zoom level and use it multiplied by the current zoom...To enhance it even more, you can get this pixel distance, to be dependant on the screen resolution and density.
Here, you can find how to calculate screen pixels to meters: https://stackoverflow.com/a/13635952/4776540
I implemented a similar thing in the following way:
Convert all locations to the screen coordinates using map.getProjection().toScreenLocation()
Use standard distance formula to determine distance from point to point (or from point to segment, if you want to detect clicks on line segments too) and if this distance is less than some threshold - click is detected.
The key point here is to use map projection to get screen coordinates. This way the decision depends on the real pixel distance on the screen, and does not depend on a zoom level.

How can I trigger the Several Functionality of Google Maps in my App

I am trying to create a maps app for a certain city that have some stored latitude and longitude for certain landmarks in the city. In the map,
you can only zoom in and zoom out within the boundaries of the city
While the app is open, when you reach a certain range of lat and long coordinates within a certain radius around the landmark, it will trigger and activity that will display details about the landmark and also a voice recording about the landmark
also, the map must also have the "directions" functionality in it, where it can show several possible ways for you to get to a certain location (like landmark) from your present location and also display the distance between two points
I've already tried a GPS program from androidhive that detects your lat and long coordinates. I'm also trying to understand how to acquire and use the google maps api. I would like to know the possible approaches in doing it since I'm still new to android.
Thanks in Advance!
you can zoom with specific mile or kmeter by this code:this is for two mile:
Display display = getWindowManager().getDefaultDisplay();
// double equatorLength = 3218; // in meters
double equatorLength = 40075004; // in meters
double widthInPixels = display.getWidth();
double metersPerPixel = equatorLength / 256;
int zoomLevel = 1;
// 2 mile=3218 mtr
while ((metersPerPixel * widthInPixels) > 3218) {
metersPerPixel /= 2;
++zoomLevel;
}
return zoomLevel;
hope this is helpfull for "you can only zoom in and zoom out within the boundaries of the city"

MapController, OSMdroid, zoomToSpan() freezes application

I use OSMdroid to display an offline map. The MapView is placed inside a Fragment. I would like to zoom the map to cover two points (top_left, bottom_right). Currently when I call zoomToSpan() in onViewCreated() the app freezes. I have tried using BoundingBoxE6 and latitude, longitude span but nothing changes.
BoundingBoxE6 bb = new BoundingBoxE6(
LocationConstants.TOP_LEFT_LATITUDE,
LocationConstants.TOP_LEFT_LONGITUDE,
LocationConstants.BOTTOM_RIGHT_LATITUDE,
LocationConstants.BOTTOM_RIGHT_LONGITUDE);
or
int latitudeSpan = (int) Math.abs(LocationConstants.TOP_LEFT_LATITUDE*1E6 - LocationConstants.BOTTOM_RIGHT_LATITUDE*1E6);
int longitudeSpan = (int) Math.abs(LocationConstants.TOP_LEFT_LONGITUDE*1E6 - LocationConstants.BOTTOM_RIGHT_LONGITUDE*1E6);
give the same results.

Drawing dotted line on google maps v2 instead of solid

Instead of having a polygon with a solid line surrounding it I want to create one with a dotted line, is this possible?
I know you could do this when you override the onDraw method of the overlay in v1 but the Overlay class does not exist anymore so how else can I achieve this?
It's currently not possible, but you may upvote this enhancement here: http://code.google.com/p/gmaps-api-issues/issues/detail?id=4633
UPDATE
Recently, Google implemented this feature for polylines and polygons in Google Maps Android API v2 and marked issue 4633 as Fixed.
See information about stroke patterns in the Shapes Guide. See an example in the Polylines and Polygons tutorial.
You can also read the corresponding blog post here:
https://maps-apis.googleblog.com/2017/02/styling-and-custom-data-for-polylines.html
First of all, take a look on the API
https://developers.google.com/maps/documentation/android/reference/com/google/android/gms/maps/model/Polyline
it is not yet possible with v2, but on v3 javascript API, it already is, look here:
https://developers.google.com/maps/documentation/javascript/overlays#PolylineSymbols
But it seems that it's possible to use this v3 javascript API in an android app, look here:
https://developers.google.com/maps/articles/android_v3
Maybe, this will help you
Find a LatLng at a distance of radius units from center LatLng on Map
now convert both these LatLngs to screenCoordinates
Use the formula used to construct a cirle x = Rsin(theta) , y = Rcos(theta)
you divide the circle into N segments and then draw polylines(drawn on map) on the circumference of the circle converting the screen coordinates to LatLngs
more the number of N more it looks like a circle , I have used N = 120 according the zoom level ,I am using 13.
private void addDottedCircle(double radius) {//radius is in kms
clearDottedCircle();
LatLng center,start,end;
Point screenPosCenter,screenPosStart,screenPosEnd;
Projection p = mMap.getProjection();
center = searchCenterMarker.getPosition();
start = new LatLng(center.latitude + radius/110.54,center.longitude);
// radius/110.54 gives the latitudinal delta we should increase so that we have a latitude at radius distance
// 1 degree latitude is approximately 110.54 kms , so the above equation gives you a rough estimate of latitude at a distance of radius distance
screenPosCenter = p.toScreenLocation(center);
screenPosStart = p.toScreenLocation(start);
double R = screenPosCenter.y - screenPosStart.y;
int N = 120;//N is the number of parts we are dividing the circle
double T = 2*Math.PI/N;
double theta = T;
screenPosEnd = new Point();
screenPosEnd.x = (int)(screenPosCenter.x-R*Math.sin(theta));
screenPosEnd.y = (int) (screenPosCenter.y-R*Math.cos(theta));
end = p.fromScreenLocation(screenPosEnd);
for(int i =0;i<N;i++){
theta+=T;
if(i%2 == 0){
//dottedCircle is a hashmap to keep reference to all the polylines added to map
dottedCircle.add(mMap.addPolyline(new PolylineOptions().add(start,end).width(5).color(Color.BLACK)));
screenPosStart.x = (int) (screenPosCenter.x-R*Math.sin(theta));
screenPosStart.y = (int) (screenPosCenter.y-R*Math.cos(theta));
start = p.fromScreenLocation(screenPosStart);
}
else{
screenPosEnd.x = (int)(screenPosCenter.x-R*Math.sin(theta));
screenPosEnd.y = (int) (screenPosCenter.y-R*Math.cos(theta));
end = p.fromScreenLocation(screenPosEnd);
}
}
}
If you are still looking for an answer have a look at this :
How to draw dashed polyline with android google map sdk v2?

Categories

Resources