Skip to content

Commit fed5832

Browse files
committed
Merge branch 'master' of https://github.com/wingkwong/geodesy
2 parents 73c123c + f64ee53 commit fed5832

File tree

4 files changed

+222
-4
lines changed

4 files changed

+222
-4
lines changed

README.md

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ A Dart library for implementing geodesic and trigonometric calculations based on
99
### Add the following line in your `pubspec.yml` file
1010

1111
```dart
12-
geodesy:
12+
geodesy:<latest_version>
1313
```
1414

1515
### Include the widget in your dart file
@@ -132,3 +132,45 @@ final pointsToCheck = <LatLng>[/* points here */];
132132
final distance = 10000;
133133
List<LatLng> geoFencedPoints = geodesy.pointsInRange(point, pointsToCheck, distance);
134134
```
135+
136+
### getRectangleBounds(List<LatLng> polygonCoords)
137+
138+
Similar to PolygonEnvelop in Python
139+
140+
```dart
141+
List<LatLng> polygonCoords = [
142+
const LatLng(37.7749, -122.4194),
143+
const LatLng(37.3382, -121.8863),
144+
const LatLng(37.7749, -121.4194),
145+
const LatLng(37.7749, -123.4194),
146+
];
147+
148+
List<LatLng> rectangleBounds = geodesy.getRectangleBounds(polygonCoords);
149+
```
150+
151+
### Great-circle distance between two points using the Haversine formula
152+
153+
Calculate the Great-Circle Distance between two Geo points
154+
155+
```dart
156+
num latitude1 = 37.7749;
157+
num longitude1 = -122.4194;
158+
num latitude2 = 37.3382;
159+
num longitude2 = -121.8863;
160+
161+
num greatCircleDistance = geodesy.greatCircleDistanceBetweenTwoGeoPoints(
162+
latitude1, longitude1, latitude2, longitude2);
163+
```
164+
165+
### calculateBoundingBox(LatLng centerPoint, num distanceInKm)
166+
167+
Given the Latitude and Longitude and distance in kilometers it calculate the bounding box value
168+
169+
```dart
170+
final centerPoint = const LatLng(
171+
37.7749, -122.4194); // Example central position (San Francisco)
172+
173+
final distanceInKm = 1.0; // Example distance in kilometers
174+
175+
final boundingBox = geodesy.calculateBoundingBox(centerPoint, distanceInKm);
176+
```

example/main.dart

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ void main() async {
1212
print('[distanceBetweenTwoGeoPoints] Distance: ' + distance.toString());
1313

1414
var l3 = const LatLng(51.4778, -0.0015);
15-
var distinationPoint =
15+
var destinationPoint =
1616
geodesy.destinationPointByDistanceAndBearing(l3, 7794.0, 300.7);
1717
print('[destinationPointByDistanceAndBearing] Lat: ' +
18-
distinationPoint.latitude.toString());
18+
destinationPoint.latitude.toString());
1919
print('[destinationPointByDistanceAndBearing] Lng: ' +
20-
distinationPoint.longitude.toString());
20+
destinationPoint.longitude.toString());
2121

2222
var l4 = const LatLng(52.205, 0.119);
2323
var l5 = const LatLng(48.857, 2.351);
@@ -57,4 +57,43 @@ void main() async {
5757
var l7 = const LatLng(1.5, 1.5);
5858
var isGeoPointInPolygon = geodesy.isGeoPointInPolygon(l7, poly);
5959
print('[isGeoPointInPolygon] :' + isGeoPointInPolygon.toString());
60+
61+
// Great-circle distance between two points using the Haversine formula
62+
num latitude1 = 37.7749;
63+
num longitude1 = -122.4194;
64+
num latitude2 = 37.3382;
65+
num longitude2 = -121.8863;
66+
67+
num greatCircleDistance = geodesy.greatCircleDistanceBetweenTwoGeoPoints(
68+
latitude1, longitude1, latitude2, longitude2);
69+
70+
print(
71+
'''[greatCircleDistance]: ${greatCircleDistance.toStringAsFixed(2)} km''');
72+
73+
// Polygon Coords
74+
List<LatLng> polygonCoords = [
75+
const LatLng(37.7749, -122.4194),
76+
const LatLng(37.3382, -121.8863),
77+
const LatLng(37.7749, -121.4194),
78+
const LatLng(37.7749, -123.4194),
79+
];
80+
81+
List<LatLng> rectangleBounds = geodesy.getRectangleBounds(polygonCoords);
82+
83+
print('[getRectangleBounds]: ');
84+
for (LatLng coord in rectangleBounds) {
85+
print(' > Latitude: ${coord.latitude}, Longitude: ${coord.longitude}');
86+
}
87+
88+
// Calculate Bounding Box
89+
// Example central position (San Francisco)
90+
final centerPoint = const LatLng(37.7749, -122.4194);
91+
// Example distance in kilometers
92+
final distanceInKm = 1.0;
93+
94+
final boundingBox = geodesy.calculateBoundingBox(centerPoint, distanceInKm);
95+
96+
print('[calculateBoundingBox]: ');
97+
print(' > Top Left: ${boundingBox[0]}');
98+
print(' > Bottom Right: ${boundingBox[1]}');
6099
}

lib/src/geodesy.dart

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,4 +229,75 @@ class Geodesy {
229229
}
230230
return geoFencedPoints;
231231
}
232+
233+
/// great-circle distance between two points using the Haversine formula
234+
num greatCircleDistanceBetweenTwoGeoPoints(
235+
num lat1, num lon1, num lat2, num lon2) {
236+
final num earthRadius = _RADIUS; // Radius of the earth in kilometers
237+
238+
num dLat = degToRadian(lat2.toDouble() - lat1.toDouble());
239+
num dLon = degToRadian(lon2.toDouble() - lon1.toDouble());
240+
241+
num a = math.sin(dLat / 2) * math.sin(dLat / 2) +
242+
math.cos(degToRadian(lat1.toDouble())) *
243+
math.cos(degToRadian(lat2.toDouble())) *
244+
math.sin(dLon / 2) *
245+
math.sin(dLon / 2);
246+
num c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a));
247+
num distance = earthRadius * c;
248+
249+
return distance;
250+
}
251+
252+
/// GetRectangleBounds
253+
254+
List<LatLng> getRectangleBounds(List<LatLng> polygonCoords) {
255+
num minLatitude = double.infinity.toDouble();
256+
num maxLatitude = double.negativeInfinity.toDouble();
257+
num minLongitude = double.infinity.toDouble();
258+
num maxLongitude = double.negativeInfinity.toDouble();
259+
260+
for (LatLng coord in polygonCoords) {
261+
if (coord.latitude < minLatitude) {
262+
minLatitude = coord.latitude;
263+
}
264+
if (coord.latitude > maxLatitude) {
265+
maxLatitude = coord.latitude;
266+
}
267+
if (coord.longitude < minLongitude) {
268+
minLongitude = coord.longitude;
269+
}
270+
if (coord.longitude > maxLongitude) {
271+
maxLongitude = coord.longitude;
272+
}
273+
}
274+
275+
List<LatLng> rectangleBounds = [
276+
LatLng(minLatitude.toDouble(), minLongitude.toDouble()),
277+
LatLng(minLatitude.toDouble(), maxLongitude.toDouble()),
278+
LatLng(maxLatitude.toDouble(), maxLongitude.toDouble()),
279+
LatLng(maxLatitude.toDouble(), minLongitude.toDouble()),
280+
];
281+
282+
return rectangleBounds;
283+
}
284+
285+
/// Bounding Box per distance in Kilometers
286+
List<LatLng> calculateBoundingBox(LatLng centerPoint, num distanceInKm) {
287+
// Earth's radius in kilometers
288+
final num radiusOfEarth = _RADIUS / 1000;
289+
// Convert latitude to radians
290+
final num latInRadians = centerPoint.latitude * (_PI / 180.0);
291+
final num degreeLatDistance =
292+
(distanceInKm / radiusOfEarth) * (180.0 / _PI);
293+
final num degreeLngDistance = degreeLatDistance / math.cos(latInRadians);
294+
final num topLat = centerPoint.latitude + degreeLatDistance;
295+
final num leftLng = centerPoint.longitude - degreeLngDistance;
296+
final num bottomLat = centerPoint.latitude - degreeLatDistance;
297+
final num rightLng = centerPoint.longitude + degreeLngDistance;
298+
final LatLng topLeft = LatLng(topLat.toDouble(), leftLng.toDouble());
299+
final LatLng bottomRight =
300+
LatLng(bottomLat.toDouble(), rightLng.toDouble());
301+
return [topLeft, bottomRight];
302+
}
232303
}

test/geodesy_test.dart

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,4 +98,70 @@ void main() {
9898
expect((geoFencedPoints.contains(pointInRange)), true);
9999
expect((geoFencedPoints.contains(pointNotInRange)), false);
100100
});
101+
102+
test('Great-Circle distance between two points using the Haversine formula',
103+
() async {
104+
const num latitude1 = 52.5200; // Latitude of the first point
105+
const num longitude1 = 13.4050; // Longitude of the first point
106+
const num latitude2 = 48.8566; // Latitude of the second point
107+
const num longitude2 = 2.3522; // Longitude of the second point
108+
109+
const num expectedDistance = 877460.0; // Expected distance in kilometers
110+
111+
final num distance = geodesy.greatCircleDistanceBetweenTwoGeoPoints(
112+
latitude1, longitude1, latitude2, longitude2);
113+
114+
expect(distance, closeTo(expectedDistance, 10.0));
115+
});
116+
117+
test('getRectangleBounds returns correct rectangle bounds', () async {
118+
List<LatLng> polygonCoords = [
119+
const LatLng(37.7749, -122.4194),
120+
const LatLng(37.3382, -121.8863),
121+
const LatLng(37.7749, -121.4194),
122+
const LatLng(37.7749, -123.4194),
123+
];
124+
125+
List<LatLng> expectedRectangleBounds = [
126+
const LatLng(37.3382, -123.4194),
127+
const LatLng(37.3382, -121.4194),
128+
const LatLng(37.7749, -121.4194),
129+
const LatLng(37.7749, -123.4194),
130+
];
131+
132+
List<LatLng> rectangleBounds = geodesy.getRectangleBounds(polygonCoords);
133+
134+
// Assert that the rectangle bounds are calculated correctly
135+
expect(rectangleBounds.length, expectedRectangleBounds.length);
136+
for (int i = 0; i < expectedRectangleBounds.length; i++) {
137+
LatLng expectedCoord = expectedRectangleBounds[i];
138+
LatLng actualCoord = rectangleBounds[i];
139+
expect(actualCoord.latitude, expectedCoord.latitude);
140+
expect(actualCoord.longitude, expectedCoord.longitude);
141+
}
142+
});
143+
144+
group('calculateBoundingBox', () {
145+
test(
146+
'''should calculate the correct bounding box for a given center point and distance''',
147+
() async {
148+
final centerPoint = const LatLng(40.0, -73.0); // Example center point
149+
final distanceInKm = 10.0; // Example distance in kilometers
150+
151+
final result = geodesy.calculateBoundingBox(centerPoint, distanceInKm);
152+
153+
// Expected coordinates for the bounding box
154+
final expectedTopLeft =
155+
const LatLng(40.09090909090909, -73.16323914050199);
156+
final expectedBottomRight =
157+
const LatLng(39.90909090909091, -72.836760859498);
158+
159+
// Check if the calculated bounding box matches the expected coordinates
160+
expect(result[0].latitude, closeTo(expectedTopLeft.latitude, 0.1));
161+
expect(result[0].longitude, closeTo(expectedTopLeft.longitude, 0.1));
162+
expect(result[1].latitude, closeTo(expectedBottomRight.latitude, 0.1));
163+
expect(result[1].longitude, closeTo(expectedBottomRight.longitude, 0.1));
164+
});
165+
});
166+
101167
}

0 commit comments

Comments
 (0)