Check if point is in polygon with Google Maps API in Android

11,179

Solution 1

You can use the PolyUtil.containsLocation method from the Google Maps Android API Utility Library. From the documentation:

public static boolean containsLocation(LatLng point, java.util.List polygon, boolean geodesic)

Computes whether the given point lies inside the specified polygon. The polygon is always considered closed, regardless of whether the last point equals the first or not. Inside is defined as not containing the South Pole -- the South Pole is always outside. The polygon is formed of great circle segments if geodesic is true, and of rhumb (loxodromic) segments otherwise.

Solution 2

A bit later response, but for future searches, you can also check if a location is inside the current visible map area by using:

// Kotlin code
var location = LatLng(-27.6016488, -48.5137219)    
val isInside = mGoogleMap.projection.visibleRegion.latLngBounds.contains(location)

Documentation link: contains (LatLng point)

Share:
11,179

Related videos on Youtube

PhiloJunkie
Author by

PhiloJunkie

Updated on June 04, 2022

Comments

  • PhiloJunkie
    PhiloJunkie almost 2 years

    I am using the Google Maps API on Android to create a puzzle. This link contains the data I used to draw African countries: World countries coordinates.

    When the user clicks on the map, a test is done to check whether it was in the right country or not.

    • point inside right country: the right country is colored in green

    • point inside another known country: the current country is colored in red

    The code below iterates the list of African countries (a country may contain multiple polygons) to find the one that contains the clicked point and compare it with the right country.

    mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
        @Override
        public void onMapClick(LatLng latLng) {
    
            if(isPointInPolygon(latLng,answerPolygon)) {
                // right answer
                Toast.makeText(MapsActivity.this, "point inside the right polygon", Toast.LENGTH_SHORT).show();
                Polygon p = mMap.addPolygon(new PolygonOptions().addAll(answerPolygon));
                p.setStrokeWidth(p.getStrokeWidth()/5);
                p.setFillColor(0x7F00FF00);
            }
            else {
                // wrong answer
                // search current polygon
                // color current polygon in red
                if (colorPolygonInRed(latLng)){
                    Polygon p = mMap.addPolygon(new PolygonOptions().addAll(answerPolygon));
                    p.setStrokeWidth(p.getStrokeWidth()/5);
                    p.setFillColor(0x7F00FF00);
                    Toast.makeText(MapsActivity.this, "point in known polygons", Toast.LENGTH_SHORT).show();
                }
                else {
                    Toast.makeText(MapsActivity.this, "point in unknown polygons", Toast.LENGTH_SHORT).show();
                }
            }
        }
    });
    

    The function isPointInPolygon() works with only one polygon on the map because it's based on geometry (ray intersect). It doesn't work in my case. For example, when I click inside Chad the country (the blue spot in this picture), Egypt is getting colored with red (my list is sorted alphabetically, so Egypt is the first one on the right of the clicked point that verifies the ray intersect condition).

    public boolean rayCastIntersect(LatLng tap, LatLng vertA, LatLng vertB) {
        double aY = vertA.latitude;
        double bY = vertB.latitude;
        double aX = vertA.longitude;
        double bX = vertB.longitude;
        double pY = tap.latitude;
        double pX = tap.longitude;
    
        if ( (aY>pY && bY>pY) || (aY<pY && bY<pY) || (aX<pX && bX<pX) ) {
            return false; // a and b can't both be above or below pt.y, and a or b must be east of pt.x
        }
    
        double m = (aY-bY) / (aX-bX);               // Rise over run
        double bee = (-aX) * m + aY;                // y = mx + b
        double x = (pY - bee) / m;                  // algebra is neat!
    
        return x > pX;
    }
    public boolean colorPolygonInRed(LatLng point){
        for (Country country:countryList){
            for (ArrayList<LatLng> polygon : country.getCoordinates()){
                if(isPointInPolygon(point,polygon)) {
                    Polygon p = mMap.addPolygon(new PolygonOptions().addAll(polygon));
                    p.setStrokeWidth(p.getStrokeWidth()/5);
                    p.setFillColor(0x7FE00808);
                    return true;
                }
            }
        }
        return false;
    }
    

    What's the right way to get the polygon which was clicked from my list?

  • PhiloJunkie
    PhiloJunkie over 7 years
    thank you @antonio for the answer! this is exactly what I was looking for.
  • Emanuel
    Emanuel over 3 years
    I get even better results from this method if the polygon is closed. That means the first point and the last point should be the same. You can check if the polygon is closed by calling var isClosed = PolyUtil.isClosedPolygon(polygon) if (!isClosed) { polygon.add(polygon[0]) }
  • Moustafa EL-Saghier
    Moustafa EL-Saghier over 2 years
    can you tell me please what is the parameter geodesic mean? i out true/false depending on what?
  • antonio
    antonio over 2 years
    If geodesic is true, The polygon is formed of great circle segments, and if false it's formed of rhumb segments (loxodromic).