Search code examples
google-mapsflutterdartgeometrygeofencing

google maps flutter check if a point inside a polygon


I'm working on flutter project using google-maps-flutter plugin, and I want to check if the user location is inside the polygon that I created on the map. There is an easy way using JavaScript api (containsLocation() method) but for flutter I only found a third party plugin,google_map_polyutil, which is only for android and I get a security worming when I run my app. Is there another way to do so??


Solution

  • I found this answer and just modified some minor things to work with dart, I ran a test on a hardcoded polygon. The list _area is my polygon and _polygons is required for my mapcontroller.

    final Set<Polygon> _polygons = {};
    List<LatLng> _area = [
    LatLng(-17.770992200, -63.207739700),
    LatLng(-17.776386600, -63.213576200),
    LatLng(-17.778348200, -63.213576200),
    LatLng(-17.786848100, -63.214262900),
    LatLng(-17.798289700, -63.211001300),
    LatLng(-17.810547700, -63.200701600),
    LatLng(-17.815450600, -63.185252100),
    LatLng(-17.816267800, -63.170660900),
    LatLng(-17.800741300, -63.153838100),
    LatLng(-17.785867400, -63.150919800),
    LatLng(-17.770501800, -63.152636400),
    LatLng(-17.759712400, -63.160361200),
    LatLng(-17.755952300, -63.169802600),
    LatLng(-17.752519100, -63.186625400),
    LatLng(-17.758404500, -63.195551800),
    LatLng(-17.770992200, -63.206538100),
    LatLng(-17.770996000, -63.207762500)];
    

    The function ended like this:

    bool _checkIfValidMarker(LatLng tap, List<LatLng> vertices) {
        int intersectCount = 0;
        for (int j = 0; j < vertices.length - 1; j++) {
          if (rayCastIntersect(tap, vertices[j], vertices[j + 1])) {
            intersectCount++;
          }
        }
    
        return ((intersectCount % 2) == 1); // odd = inside, even = outside;
      }
    
      bool 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;
      }
    
    

    Notice the polygons property and the onTap method. I was trying to check if the marker created in my map was inside my polygon:

    GoogleMap(
                              initialCameraPosition: CameraPosition(
                                target: target, //LatLng(0, 0),
                                zoom: 16,
                              ),
                              zoomGesturesEnabled: true,
                              markers: markers,
                              polygons: _polygons,
                              onMapCreated: (controller) =>
                                  _mapController = controller,
                              onTap: (latLng) {
                                _getAddress(latLng);
                              },
                            )
    
    

    Then i just used the following call in my _getAddress method:

    _checkIfValidMarker(latLng, _area);
    

    I hope it helps you to create what you need.