Skip to content

Instantly share code, notes, and snippets.

@febritecno
Created November 4, 2024 05:09
Show Gist options
  • Save febritecno/536caa9b07318fc0ca8e51fd6295a6b3 to your computer and use it in GitHub Desktop.
Save febritecno/536caa9b07318fc0ca8e51fd6295a6b3 to your computer and use it in GitHub Desktop.
how handle multipolygon
import 'dart:math';
/// Checks if a point is inside any of the geofences
bool isInsideGeofences(dynamic geofences, double lat, double lng) {
// Iterate through each geofence in the list
for (var geofence in geofences) {
// Each geofence is an array with one polygon
var polygon = geofence[0];
if (isPointInPolygon(lat, lng, polygon)) {
return true;
}
}
return false;
}
/// Checks if a point is inside a specific polygon using Ray Casting algorithm
bool isPointInPolygon(double lat, double lng, List<List<double>> polygon) {
bool isInside = false;
int j = polygon.length - 1;
for (int i = 0; i < polygon.length; i++) {
// Get current and next point coordinates
double currentLat = polygon[i][1];
double currentLng = polygon[i][0];
double prevLat = polygon[j][1];
double prevLng = polygon[j][0];
// Check if point is within the polygon bounds
if (((currentLat > lat) != (prevLat > lat)) &&
(lng < (prevLng - currentLng) * (lat - currentLat) /
(prevLat - currentLat) + currentLng)) {
isInside = !isInside;
}
j = i;
}
return isInside;
}
/// Helper function to check if point is within polygon bounds
bool isPointInBounds(double lat, double lng, List<List<double>> polygon) {
double minLat = double.infinity;
double maxLat = -double.infinity;
double minLng = double.infinity;
double maxLng = -double.infinity;
for (var point in polygon) {
minLat = min(minLat, point[1]);
maxLat = max(maxLat, point[1]);
minLng = min(minLng, point[0]);
maxLng = max(maxLng, point[0]);
}
return lat >= minLat && lat <= maxLat && lng >= minLng && lng <= maxLng;
}
// Example usage:
void main() {
var geofences = [
[
[
[
106.62228363256,
-6.1135767313781
],
[
106.6875149558,
-6.0994096811751
],
[
106.68991821508,
-6.1454938899684
],
[
106.63266914586,
-6.14924872414
],
[
106.6152455161,
-6.1337171928233
],
[
106.62228363256,
-6.1135767313781
],
[
106.62228363256,
-6.1135767313781
],
[
106.62228363256,
-6.1135767313781
],
[
106.62228363256,
-6.1135767313781
],
[
106.62228363256,
-6.1135767313781
],
[
106.62228363256,
-6.1135767313781
]
]
],
[
[
[
106.60734909277,
-6.0893549021962
],
[
106.65867584447,
-6.0861117290764
],
[
106.61215561132,
-6.1081307824039
],
[
106.60734909277,
-6.0893549021962
]
]
],
[
[
[
106.64401556055,
-6.1035327059797
],
[
106.66873479883,
-6.1190651155563
],
[
106.63354421655,
-6.1289646576213
],
[
106.62616277734,
-6.1054102739414
],
[
106.64401556055,
-6.1035327059797
]
]
]
];
// Test some locations
//-6.130824125494702, 106.64221594991493
double currentLat = -6.130824125494702;
double currentLng = 106.64221594991493;
bool isInside = isInsideGeofences(geofences, currentLat, currentLng);
print('Location is ${isInside ? "inside" : "outside"} the geofences');
}
//// raw response data
[
{
type: MultiPolygon,
coordinates: [
[
[
[
106.62228363256,
-6.1135767313781
],
[
106.6875149558,
-6.0994096811751
],
[
106.68991821508,
-6.1454938899684
],
[
106.63266914586,
-6.14924872414
],
[
106.6152455161,
-6.1337171928233
],
[
106.62228363256,
-6.1135767313781
],
[
106.62228363256,
-6.1135767313781
],
[
106.62228363256,
-6.1135767313781
],
[
106.62228363256,
-6.1135767313781
],
[
106.62228363256,
-6.1135767313781
],
[
106.62228363256,
-6.1135767313781
]
]
],
[
[
[
106.60734909277,
-6.0893549021962
],
[
106.65867584447,
-6.0861117290764
],
[
106.61215561132,
-6.1081307824039
],
[
106.60734909277,
-6.0893549021962
]
]
]
]
},
{
type: MultiPolygon,
coordinates: [
[
[
[
106.64401556055,
-6.1035327059797
],
[
106.66873479883,
-6.1190651155563
],
[
106.63354421655,
-6.1289646576213
],
[
106.62616277734,
-6.1054102739414
],
[
106.64401556055,
-6.1035327059797
]
]
]
]
}
]
@febritecno
Copy link
Author

febritecno commented Nov 4, 2024

class MultiPolygon {
  static merge(multiPolygons) {
    var mergedCoordinates = [];
    for (var polygon in multiPolygons) {
      if (polygon['type'] == 'MultiPolygon' &&
          polygon.containsKey('coordinates')) {
        for (var coordinatesGroup in polygon['coordinates']) {
          mergedCoordinates.addAll([coordinatesGroup]);
        }
      }
    }
    return mergedCoordinates;
  }

  /// Checks if a point is inside a specific polygon using Ray Casting algorithm
  static bool isInsideZones(dynamic geofences, double lat, double lng) {
    bool isPointInPolygon(double lat, double lng, List<List<double>> polygon) {
      if (polygon.length < 3) return false;

      bool isInside = false;
      int j = polygon.length - 1;

      for (int i = 0; i < polygon.length; i++) {
        double currentLat = polygon[i][1];
        double currentLng = polygon[i][0];
        double prevLat = polygon[j][1];
        double prevLng = polygon[j][0];

        if (((currentLat > lat) != (prevLat > lat)) &&
            (lng <
                (prevLng - currentLng) *
                        (lat - currentLat) /
                        (prevLat - currentLat) +
                    currentLng)) {
          isInside = !isInside;
        }
        j = i;
      }

      return isInside;
    }

    try {
      if (geofences == null) return false;
      List<List<List<List<double>>>> typedZones = [];

      if (geofences is List) {
        for (var zone in geofences) {
          if (zone is List && zone.isNotEmpty) {
            List<List<List<double>>> polygonGroup = [];
            for (var polygon in zone) {
              if (polygon is List) {
                List<List<double>> coordinates = [];
                for (var point in polygon) {
                  if (point is List && point.length >= 2) {
                    try {
                      double lng = double.parse(point[0].toString());
                      double lat = double.parse(point[1].toString());
                      coordinates.add([lng, lat]);
                    } catch (e) {
                      debugPrint('Error parsing coordinate: $e');
                      continue;
                    }
                  }
                }
                if (coordinates.isNotEmpty) {
                  polygonGroup.add(coordinates);
                }
              }
            }
            if (polygonGroup.isNotEmpty) {
              typedZones.add(polygonGroup);
            }
          }
        }
      }

      // Check each polygon in the zones
      for (var zoneGroup in typedZones) {
        for (var polygon in zoneGroup) {
          if (isPointInPolygon(lat, lng, polygon)) {
            return true;
          }
        }
      }

      return false;
    } catch (e) {
      debugPrint('Error checking zones: $e');
      return false;
    }
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment