Search code examples
javaandroidgoogle-maps-markersgoogle-maps-android-api-2google-maps-api-2

How to tell if a Marker is in a Polygon googleMap v2


I've got a Google Map with Polygons, I've got everything to work except this last part which is detect if a Marker is already inside a Polygon.The current situation is when I touch a Polygon it will add the Marker"which is correct" but if I touch the Polygon in a different spot it will remove the Marker and add a new one. What I want to happen is if a Marker is already within those points don't add a new one. My code is below any help would be appreciate.

public void onMapClick(LatLng point) {


    for (int j = 0; j < arrPolygons.size(); j++) {

        if (isPointInPolygon(point, arrPolygons.get(j).getPoints())) {

        if (marker != null) {
                marker.remove();
                marker = null;
                Log.v("Marker", "Removing Marker");
            }else{
                marker = googleMap.addMarker(new MarkerOptions()
                        .position(point)
                        .title("test")
                        .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED)));
                Log.v("Marker", "ADDing Marker");
            }
        }
    }

Any help would be appreciated.


Solution

  • The easiest way to do this would be using the Google Maps Android API Utility Library, which contains the PolyUtil class.

    First import the library by adding the current version to your build.gradle, currently 0.3.4 for example:

    dependencies {
        compile fileTree(dir: 'libs', include: ['*.jar'])
        compile 'com.android.support:appcompat-v7:22.1.1'
        compile 'com.google.android.gms:play-services-maps:7.3.0'
        compile 'com.google.maps.android:android-maps-utils:0.3.4'
    }
    

    For this simple example we'll assume the Map Activity class definition and member variables look like this, and only one Polygon defined in polygonList:

    import com.google.maps.android.PolyUtil;
    //other imports.....
    
    public class MapsActivity extends AppCompatActivity implements OnMapReadyCallback {
    
        private GoogleMap mMap;
        private Marker marker;
        List<LatLng> polygonList = new ArrayList<LatLng>();
        //.............
    

    You would then set up your GoogleMap.OnMapClickListener like this in order to only add one Marker inside the Polygon.:

      mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
    
            @Override
            public void onMapClick(LatLng point) {
    
                if (PolyUtil.containsLocation(point, polygonList, false)) {
    
                    if (marker == null) {
                        //only add Marker if there is not one already inside the Polygon
                        marker = mMap.addMarker(new MarkerOptions()
                                .position(point)
                                .title("test")
                                .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED)));
                        Log.v("Marker", "ADDing Marker");
    
                    }
    
                }
            }
        });
    

    Multiple Polygons, Multiple Markers Solution:

    In order to make it work with multiple Ploygons, you could use a POJO to store Polygon/Marker pairs:

    public class PolyMarkerObject{
        Polygon polygon;
        Marker marker;
    }
    

    Then define a new member variable polyMarkerList:

    public class MapsActivity extends AppCompatActivity implements OnMapReadyCallback {
    
        private GoogleMap mMap;
        List<PolyMarkerObject> polyMarkerList = new ArrayList<>();
        //.............
    

    Add each Polygon to the list when drawing it:

        List<LatLng> newPolygon = new ArrayList<>();
        //set up the points in the Polygon.......
    
        Polygon p = mMap.addPolygon(new PolygonOptions()
                .addAll(newPolygon)
                .strokeColor(Color.RED)
                .fillColor(Color.BLUE));
    
        PolyMarkerObject newPolyMarkerObj = new PolyMarkerObject();
        newPolyMarkerObj.polygon = p;
        polyMarkerList.add(newPolyMarkerObj);
    

    Then cycle through the list on each Map click to see whether the current Ploygon already has a Marker. If it does not have a Marker already, then remove any Marker already placed in a different Polygon, and create one in the current Polygon:

     mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
    
            @Override
            public void onMapClick(LatLng point) {
    
                for (PolyMarkerObject pmObj : polyMarkerList) {
                    //only add Marker if there is not one already inside the Polygon
                    if (PolyUtil.containsLocation(point, pmObj.polygon.getPoints(), false)) {
                        if (pmObj.marker == null) {
    
                            //Add Marker to current Polygon
                            Marker newMarker = mMap.addMarker(new MarkerOptions()
                                    .position(point)
                                    .title("test")
                                    .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED)));
    
                            pmObj.marker = newMarker;
                            Log.v("Marker", "ADDing Marker");
                            break;
                        }
    
                    }
                }
            }
        });
    

    Multiple Polygons, One Marker Solution:

    In this case, you just need one Marker reference, and a list of Polygons:

    public class MapsActivity extends AppCompatActivity implements OnMapReadyCallback {
    
        private GoogleMap mMap;
        Marker marker;
        List<Polygon> polyList = new ArrayList<>();
        //................
    

    Add the Polygon to the list when it's added to the Map:

        List<LatLng> newPolygon = new ArrayList<>();
        //set up the points in the Polygon.......
    
        Polygon p = mMap.addPolygon(new PolygonOptions()
                .addAll(newPolygon)
                .strokeColor(Color.RED)
                .fillColor(Color.BLUE));
    
        polyList.add(p);
    

    Then, in the Map click listener, you have two cases, one for if the Marker reference is null (no Marker added yet), and one for if the Marker is in a different Polygon. If the Marker is in the current Polygon already, it will not be moved.

     mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
    
            @Override
            public void onMapClick(LatLng point) {
    
                for (Polygon pObj : polyList) {
                    //find Polygon user tapped inside of
                    if (PolyUtil.containsLocation(point, pObj.getPoints(), false)) {
                        //first case, no Marker
                        if (marker == null) {
    
                            //Add Marker to current Polygon
                            marker = mMap.addMarker(new MarkerOptions()
                                    .position(point)
                                    .title("test")
                                    .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED)));
    
                            Log.v("Marker", "ADDing first Marker");
                            break;
                        }
                        else if (!PolyUtil.containsLocation(marker.getPosition(), pObj.getPoints(), false)) {
                            //Marker exists already in a different Polygon
                            //remove Marker from previous Polygon
                            marker.remove();
                            //Add Marker to current Polygon
                            marker = mMap.addMarker(new MarkerOptions()
                                    .position(point)
                                    .title("test")
                                    .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED)));
    
                            Log.v("Marker", "Moving Marker to new Polygon");
                            break;
                        }
    
                    }
                }
            }
        });