Skip to content

Commit

Permalink
Merge pull request #24 from wingkwong/develop
Browse files Browse the repository at this point in the history
0.5.0 Release
  • Loading branch information
wingkwong authored Jun 18, 2023
2 parents 07e3bfb + 3806a2f commit f64ee53
Show file tree
Hide file tree
Showing 4 changed files with 222 additions and 4 deletions.
44 changes: 43 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ A Dart library for implementing geodesic and trigonometric calculations based on
### Add the following line in your `pubspec.yml` file

```dart
geodesy:
geodesy:<latest_version>
```

### Include the widget in your dart file
Expand Down Expand Up @@ -132,3 +132,45 @@ final pointsToCheck = <LatLng>[/* points here */];
final distance = 10000;
List<LatLng> geoFencedPoints = geodesy.pointsInRange(point, pointsToCheck, distance);
```

### getRectangleBounds(List<LatLng> polygonCoords)

Similar to PolygonEnvelop in Python

```dart
List<LatLng> polygonCoords = [
const LatLng(37.7749, -122.4194),
const LatLng(37.3382, -121.8863),
const LatLng(37.7749, -121.4194),
const LatLng(37.7749, -123.4194),
];
List<LatLng> rectangleBounds = geodesy.getRectangleBounds(polygonCoords);
```

### Great-circle distance between two points using the Haversine formula

Calculate the Great-Circle Distance between two Geo points

```dart
num latitude1 = 37.7749;
num longitude1 = -122.4194;
num latitude2 = 37.3382;
num longitude2 = -121.8863;
num greatCircleDistance = geodesy.greatCircleDistanceBetweenTwoGeoPoints(
latitude1, longitude1, latitude2, longitude2);
```

### calculateBoundingBox(LatLng centerPoint, num distanceInKm)

Given the Latitude and Longitude and distance in kilometers it calculate the bounding box value

```dart
final centerPoint = const LatLng(
37.7749, -122.4194); // Example central position (San Francisco)
final distanceInKm = 1.0; // Example distance in kilometers
final boundingBox = geodesy.calculateBoundingBox(centerPoint, distanceInKm);
```
45 changes: 42 additions & 3 deletions example/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ void main() async {
print('[distanceBetweenTwoGeoPoints] Distance: ' + distance.toString());

var l3 = const LatLng(51.4778, -0.0015);
var distinationPoint =
var destinationPoint =
geodesy.destinationPointByDistanceAndBearing(l3, 7794.0, 300.7);
print('[destinationPointByDistanceAndBearing] Lat: ' +
distinationPoint.latitude.toString());
destinationPoint.latitude.toString());
print('[destinationPointByDistanceAndBearing] Lng: ' +
distinationPoint.longitude.toString());
destinationPoint.longitude.toString());

var l4 = const LatLng(52.205, 0.119);
var l5 = const LatLng(48.857, 2.351);
Expand Down Expand Up @@ -57,4 +57,43 @@ void main() async {
var l7 = const LatLng(1.5, 1.5);
var isGeoPointInPolygon = geodesy.isGeoPointInPolygon(l7, poly);
print('[isGeoPointInPolygon] :' + isGeoPointInPolygon.toString());

// Great-circle distance between two points using the Haversine formula
num latitude1 = 37.7749;
num longitude1 = -122.4194;
num latitude2 = 37.3382;
num longitude2 = -121.8863;

num greatCircleDistance = geodesy.greatCircleDistanceBetweenTwoGeoPoints(
latitude1, longitude1, latitude2, longitude2);

print(
'''[greatCircleDistance]: ${greatCircleDistance.toStringAsFixed(2)} km''');

// Polygon Coords
List<LatLng> polygonCoords = [
const LatLng(37.7749, -122.4194),
const LatLng(37.3382, -121.8863),
const LatLng(37.7749, -121.4194),
const LatLng(37.7749, -123.4194),
];

List<LatLng> rectangleBounds = geodesy.getRectangleBounds(polygonCoords);

print('[getRectangleBounds]: ');
for (LatLng coord in rectangleBounds) {
print(' > Latitude: ${coord.latitude}, Longitude: ${coord.longitude}');
}

// Calculate Bounding Box
// Example central position (San Francisco)
final centerPoint = const LatLng(37.7749, -122.4194);
// Example distance in kilometers
final distanceInKm = 1.0;

final boundingBox = geodesy.calculateBoundingBox(centerPoint, distanceInKm);

print('[calculateBoundingBox]: ');
print(' > Top Left: ${boundingBox[0]}');
print(' > Bottom Right: ${boundingBox[1]}');
}
71 changes: 71 additions & 0 deletions lib/src/geodesy.dart
Original file line number Diff line number Diff line change
Expand Up @@ -229,4 +229,75 @@ class Geodesy {
}
return geoFencedPoints;
}

/// great-circle distance between two points using the Haversine formula
num greatCircleDistanceBetweenTwoGeoPoints(
num lat1, num lon1, num lat2, num lon2) {
final num earthRadius = _RADIUS; // Radius of the earth in kilometers

num dLat = degToRadian(lat2.toDouble() - lat1.toDouble());
num dLon = degToRadian(lon2.toDouble() - lon1.toDouble());

num a = math.sin(dLat / 2) * math.sin(dLat / 2) +
math.cos(degToRadian(lat1.toDouble())) *
math.cos(degToRadian(lat2.toDouble())) *
math.sin(dLon / 2) *
math.sin(dLon / 2);
num c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a));
num distance = earthRadius * c;

return distance;
}

/// GetRectangleBounds
List<LatLng> getRectangleBounds(List<LatLng> polygonCoords) {
num minLatitude = double.infinity.toDouble();
num maxLatitude = double.negativeInfinity.toDouble();
num minLongitude = double.infinity.toDouble();
num maxLongitude = double.negativeInfinity.toDouble();

for (LatLng coord in polygonCoords) {
if (coord.latitude < minLatitude) {
minLatitude = coord.latitude;
}
if (coord.latitude > maxLatitude) {
maxLatitude = coord.latitude;
}
if (coord.longitude < minLongitude) {
minLongitude = coord.longitude;
}
if (coord.longitude > maxLongitude) {
maxLongitude = coord.longitude;
}
}

List<LatLng> rectangleBounds = [
LatLng(minLatitude.toDouble(), minLongitude.toDouble()),
LatLng(minLatitude.toDouble(), maxLongitude.toDouble()),
LatLng(maxLatitude.toDouble(), maxLongitude.toDouble()),
LatLng(maxLatitude.toDouble(), minLongitude.toDouble()),
];

return rectangleBounds;
}

/// Bounding Box per distance in Kilometers
List<LatLng> calculateBoundingBox(LatLng centerPoint, num distanceInKm) {
// Earth's radius in kilometers
final num radiusOfEarth = _RADIUS / 1000;
// Convert latitude to radians
final num latInRadians = centerPoint.latitude * (_PI / 180.0);
final num degreeLatDistance =
(distanceInKm / radiusOfEarth) * (180.0 / _PI);
final num degreeLngDistance = degreeLatDistance / math.cos(latInRadians);
final num topLat = centerPoint.latitude + degreeLatDistance;
final num leftLng = centerPoint.longitude - degreeLngDistance;
final num bottomLat = centerPoint.latitude - degreeLatDistance;
final num rightLng = centerPoint.longitude + degreeLngDistance;
final LatLng topLeft = LatLng(topLat.toDouble(), leftLng.toDouble());
final LatLng bottomRight =
LatLng(bottomLat.toDouble(), rightLng.toDouble());
return [topLeft, bottomRight];
}
}
66 changes: 66 additions & 0 deletions test/geodesy_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -98,4 +98,70 @@ void main() {
expect((geoFencedPoints.contains(pointInRange)), true);
expect((geoFencedPoints.contains(pointNotInRange)), false);
});

test('Great-Circle distance between two points using the Haversine formula',
() async {
const num latitude1 = 52.5200; // Latitude of the first point
const num longitude1 = 13.4050; // Longitude of the first point
const num latitude2 = 48.8566; // Latitude of the second point
const num longitude2 = 2.3522; // Longitude of the second point

const num expectedDistance = 877460.0; // Expected distance in kilometers

final num distance = geodesy.greatCircleDistanceBetweenTwoGeoPoints(
latitude1, longitude1, latitude2, longitude2);

expect(distance, closeTo(expectedDistance, 10.0));
});

test('getRectangleBounds returns correct rectangle bounds', () async {
List<LatLng> polygonCoords = [
const LatLng(37.7749, -122.4194),
const LatLng(37.3382, -121.8863),
const LatLng(37.7749, -121.4194),
const LatLng(37.7749, -123.4194),
];

List<LatLng> expectedRectangleBounds = [
const LatLng(37.3382, -123.4194),
const LatLng(37.3382, -121.4194),
const LatLng(37.7749, -121.4194),
const LatLng(37.7749, -123.4194),
];

List<LatLng> rectangleBounds = geodesy.getRectangleBounds(polygonCoords);

// Assert that the rectangle bounds are calculated correctly
expect(rectangleBounds.length, expectedRectangleBounds.length);
for (int i = 0; i < expectedRectangleBounds.length; i++) {
LatLng expectedCoord = expectedRectangleBounds[i];
LatLng actualCoord = rectangleBounds[i];
expect(actualCoord.latitude, expectedCoord.latitude);
expect(actualCoord.longitude, expectedCoord.longitude);
}
});

group('calculateBoundingBox', () {
test(
'''should calculate the correct bounding box for a given center point and distance''',
() async {
final centerPoint = const LatLng(40.0, -73.0); // Example center point
final distanceInKm = 10.0; // Example distance in kilometers

final result = geodesy.calculateBoundingBox(centerPoint, distanceInKm);

// Expected coordinates for the bounding box
final expectedTopLeft =
const LatLng(40.09090909090909, -73.16323914050199);
final expectedBottomRight =
const LatLng(39.90909090909091, -72.836760859498);

// Check if the calculated bounding box matches the expected coordinates
expect(result[0].latitude, closeTo(expectedTopLeft.latitude, 0.1));
expect(result[0].longitude, closeTo(expectedTopLeft.longitude, 0.1));
expect(result[1].latitude, closeTo(expectedBottomRight.latitude, 0.1));
expect(result[1].longitude, closeTo(expectedBottomRight.longitude, 0.1));
});
});

}

0 comments on commit f64ee53

Please sign in to comment.