Touch detection on polyline in Google Maps Android API v2
Asked Answered
G

4

13

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.

Galacto answered 11/4, 2015 at 6:37 Comment(3)
i have the following questions for you to provide a better answer than i currently did: 1. where is the posted code residing? is it in an onMapClickListener? dispatchTouchEvent? something else? 2. when you say you want to detect a polyline touch; do you mean a click on the line or would you also like to enable swiping or other touch gestures?Taffy
i used this code inside onMapLongClickListener..Galacto
OK, so please try onMapClickListener (long click actually is designed to do what you described which is only to be called following a lengthy click on the item w/o movement) and also look at my answer :)Taffy
N
1

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;
                }
            });
Novgorod answered 15/4, 2015 at 9:39 Comment(6)
All you need is a transparent image and replace it with markersNovgorod
let me check this methodGalacto
your method is correct..but, here already, polyline coordinates list size will cross more than FIFTY THOUSAND(50k). also, arraylist out of memory error came..i could not store all polyline values in one list..Galacto
i suggest instead of keeping all coordinates of the smooth path, just store the coordinates of the steps array, it will work perfectly fine; however somewhere it will not consume the click in case of low zoom level but at higher zoom level it will not make any differenceNovgorod
i could not understand the storing coordinates in steps array.. how can i store it?. i know normal arraylist.Galacto
Let us continue this discussion in chat.Galacto
T
0

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.

Taffy answered 15/4, 2015 at 6:6 Comment(7)
i tried this royiby. but, i got error in these two params isGeodesic, tolerance. where can i get values for those params.. me to searched in google and got above that line..Galacto
These 2 parameters are regarding your preferences of detection, what values did you try?Taffy
isGeodesic is a boolean - since you're detecting a line i would try both true and false and see which works best. tolerance is also a parameter regarding how light do you want the touch to be to set it off so i would start with 0 which is no tollerance so the slightest touch will set it off for testing. After you get it running try fine tuning it to make it good but not annoying (you don't want any bump to set it off i hope).Taffy
I tried this roy..PolyUtil.isLocationOnPath(points, mPolylines, true, 0.0) ; but, i got this error.....The method isLocationOnPath(LatLng, List<LatLng>, boolean, double) in the type PolyUtil is not applicable for the arguments (LatLng, List<Polyline>, boolean, double)Galacto
map.setOnMapClickListener(new GoogleMap.OnMapClickListener() { @Override public void onMapClick(LatLng points) { PolyUtil.isLocationOnPath(points, mPolylines, true, 0.0) ; } });Galacto
It tells you what's wrong, please pay attention: List<Polyline> is not List<LatLng>. what's the question in the second comment?Taffy
Let us continue this discussion in chat.Taffy
T
0

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://mcmap.net/q/909178/-how-to-scale-a-mapview-from-pixels-to-meters

Tranquilizer answered 18/4, 2015 at 0:12 Comment(0)
C
0

I implemented a similar thing in the following way:

  1. Convert all locations to the screen coordinates using map.getProjection().toScreenLocation()
  2. 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.

Chirr answered 19/4, 2015 at 10:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.