Skip to content

Commit a7147f2

Browse files
authored
Merge pull request #26 from wingkwong/develop
0.6.0
2 parents fed5832 + 1743e51 commit a7147f2

File tree

7 files changed

+245
-15
lines changed

7 files changed

+245
-15
lines changed

CHANGELOG.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
# CHANGELOG
22

3+
## 0.6.0
4+
5+
- Add findPolygonCentroid
6+
- Add getPolygonIntersection
7+
38
## 0.5.0
4-
- greatCircleDistanceBetweenTwoGeoPoints
5-
- getRectangleBounds
6-
- calculateBoundingBox
9+
- Add greatCircleDistanceBetweenTwoGeoPoints
10+
- Add getRectangleBounds
11+
- Add calculateBoundingBox
712

813
## 0.4.2
914
- Removed pedantic

README.md

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -148,18 +148,18 @@ Similar to PolygonEnvelop in Python
148148
List<LatLng> rectangleBounds = geodesy.getRectangleBounds(polygonCoords);
149149
```
150150

151-
### Great-circle distance between two points using the Haversine formula
151+
### greatCircleDistanceBetweenTwoGeoPoints(num lat1, num lng1, num lat2, num lng2)
152152

153-
Calculate the Great-Circle Distance between two Geo points
153+
Calculate the Great-Circle Distance between two Geo points using the Haversine formula
154154

155155
```dart
156156
num latitude1 = 37.7749;
157-
num longitude1 = -122.4194;
158-
num latitude2 = 37.3382;
159-
num longitude2 = -121.8863;
157+
num longitude1 = -122.4194;
158+
num latitude2 = 37.3382;
159+
num longitude2 = -121.8863;
160160
161-
num greatCircleDistance = geodesy.greatCircleDistanceBetweenTwoGeoPoints(
162-
latitude1, longitude1, latitude2, longitude2);
161+
num greatCircleDistance = geodesy.greatCircleDistanceBetweenTwoGeoPoints(
162+
latitude1, longitude1, latitude2, longitude2);
163163
```
164164

165165
### calculateBoundingBox(LatLng centerPoint, num distanceInKm)
@@ -174,3 +174,43 @@ Given the Latitude and Longitude and distance in kilometers it calculate the bou
174174
175175
final boundingBox = geodesy.calculateBoundingBox(centerPoint, distanceInKm);
176176
```
177+
178+
## findPolygonCentroid(List<LatLng> polygon)
179+
180+
```dart
181+
List<LatLng> polygon = [
182+
const LatLng(0, 0),
183+
const LatLng(4, 0),
184+
const LatLng(4, 4),
185+
const LatLng(0, 4)
186+
];
187+
188+
LatLng centroid = geodesy.findPolygonCentroid(polygon);
189+
print("Centroid: ${centroid.latitude}, ${centroid.longitude}");
190+
```
191+
192+
## getPolygonIntersection(List<LatLng> polygon1, List<LatLng> polygon2)
193+
194+
```dart
195+
final List<LatLng> polygon1 = [
196+
const LatLng(0, 0),
197+
const LatLng(0, 2),
198+
const LatLng(2, 2),
199+
const LatLng(2, 0),
200+
];
201+
202+
final List<LatLng> polygon2 = [
203+
const LatLng(1, 1),
204+
const LatLng(1, 3),
205+
const LatLng(3, 3),
206+
const LatLng(3, 1),
207+
];
208+
209+
final List<LatLng> intersectionPoints =
210+
geodesy.getPolygonIntersection(polygon1, polygon2);
211+
212+
print('Intersection Points:');
213+
for (final point in intersectionPoints) {
214+
print('Latitude: ${point.latitude}, Longitude: ${point.longitude}');
215+
}
216+
```

analysis_options.yaml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@
22
include: package:lints/core.yaml
33

44
analyzer:
5-
strong-mode:
6-
implicit-casts: false
7-
implicit-dynamic: false
85
errors:
96
missing_return: error
107
missing_required_param: error

example/main.dart

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,4 +96,40 @@ void main() async {
9696
print('[calculateBoundingBox]: ');
9797
print(' > Top Left: ${boundingBox[0]}');
9898
print(' > Bottom Right: ${boundingBox[1]}');
99+
100+
// Polygon Centroid
101+
List<LatLng> polygon = [
102+
const LatLng(0, 0),
103+
const LatLng(4, 0),
104+
const LatLng(4, 4),
105+
const LatLng(0, 4)
106+
];
107+
108+
LatLng centroid = geodesy.findPolygonCentroid(polygon);
109+
110+
print("Centroid: ${centroid.latitude}, ${centroid.longitude}");
111+
112+
// Polygon Intersection
113+
114+
final List<LatLng> polygon1 = [
115+
const LatLng(0, 0),
116+
const LatLng(0, 2),
117+
const LatLng(2, 2),
118+
const LatLng(2, 0),
119+
];
120+
121+
final List<LatLng> polygon2 = [
122+
const LatLng(1, 1),
123+
const LatLng(1, 3),
124+
const LatLng(3, 3),
125+
const LatLng(3, 1),
126+
];
127+
128+
final List<LatLng> intersectionPoints =
129+
geodesy.getPolygonIntersection(polygon1, polygon2);
130+
131+
print('Intersection Points:');
132+
for (final point in intersectionPoints) {
133+
print('Latitude: ${point.latitude}, Longitude: ${point.longitude}');
134+
}
99135
}

lib/src/geodesy.dart

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,6 @@ class Geodesy {
250250
}
251251

252252
/// GetRectangleBounds
253-
254253
List<LatLng> getRectangleBounds(List<LatLng> polygonCoords) {
255254
num minLatitude = double.infinity.toDouble();
256255
num maxLatitude = double.negativeInfinity.toDouble();
@@ -300,4 +299,113 @@ class Geodesy {
300299
LatLng(bottomLat.toDouble(), rightLng.toDouble());
301300
return [topLeft, bottomRight];
302301
}
302+
303+
/// finds the centroid of polygons
304+
LatLng findPolygonCentroid(List<LatLng> polygons) {
305+
num x = 0;
306+
num y = 0;
307+
num signedArea = 0;
308+
309+
num vertexCount = polygons.length;
310+
311+
for (int i = 0; i < vertexCount; i++) {
312+
final LatLng currentVertex = polygons[i];
313+
final LatLng nextVertex = polygons[(i + 1) % vertexCount.toInt()];
314+
315+
num a = currentVertex.longitude * nextVertex.latitude -
316+
nextVertex.longitude * currentVertex.latitude;
317+
signedArea += a;
318+
x += (currentVertex.longitude + nextVertex.longitude) * a;
319+
y += (currentVertex.latitude + nextVertex.latitude) * a;
320+
}
321+
322+
signedArea *= 0.5;
323+
x /= (6 * signedArea);
324+
y /= (6 * signedArea);
325+
326+
// Return the centroid as LatLng object
327+
return LatLng(
328+
y.toDouble(),
329+
x.toDouble(),
330+
);
331+
}
332+
333+
/// Polygon Intersection
334+
List<LatLng> getPolygonIntersection(
335+
List<LatLng> polygon1, List<LatLng> polygon2) {
336+
final List<LatLng> intersectionPoints = <LatLng>[];
337+
338+
for (int i = 0; i < polygon1.length; i++) {
339+
final int j = (i + 1) % polygon1.length;
340+
final LatLng edge1Start = polygon1[i];
341+
final LatLng edge1End = polygon1[j];
342+
343+
for (int k = 0; k < polygon2.length; k++) {
344+
final int l = (k + 1) % polygon2.length;
345+
final LatLng edge2Start = polygon2[k];
346+
final LatLng edge2End = polygon2[l];
347+
348+
final LatLng? intersection =
349+
_getLineIntersection(edge1Start, edge1End, edge2Start, edge2End);
350+
if (intersection != null) {
351+
intersectionPoints.add(intersection);
352+
}
353+
}
354+
}
355+
return intersectionPoints;
356+
}
357+
358+
LatLng? _getLineIntersection(
359+
LatLng start1, LatLng end1, LatLng start2, LatLng end2) {
360+
final num x1 = start1.latitude;
361+
final num y1 = start1.longitude;
362+
final num x2 = end1.latitude;
363+
final num y2 = end1.longitude;
364+
final num x3 = start2.latitude;
365+
final num y3 = start2.longitude;
366+
final num x4 = end2.latitude;
367+
final num y4 = end2.longitude;
368+
369+
final num denominator = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
370+
if (denominator == 0) {
371+
return null; // Lines are parallel or coincident
372+
}
373+
374+
final num intersectionX =
375+
((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) /
376+
denominator;
377+
final num intersectionY =
378+
((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) /
379+
denominator;
380+
381+
final LatLng intersection =
382+
LatLng(intersectionX.toDouble(), intersectionY.toDouble());
383+
384+
if (_isPointOnLine(intersection, start1, end1) &&
385+
_isPointOnLine(intersection, start2, end2)) {
386+
return intersection;
387+
} else {
388+
return null;
389+
}
390+
}
391+
392+
bool _isPointOnLine(LatLng point, LatLng lineStart, LatLng lineEnd) {
393+
final minX = lineStart.latitude < lineEnd.latitude
394+
? lineStart.latitude
395+
: lineEnd.latitude;
396+
final maxX = lineStart.latitude > lineEnd.latitude
397+
? lineStart.latitude
398+
: lineEnd.latitude;
399+
final minY = lineStart.longitude < lineEnd.longitude
400+
? lineStart.longitude
401+
: lineEnd.longitude;
402+
final maxY = lineStart.longitude > lineEnd.longitude
403+
? lineStart.longitude
404+
: lineEnd.longitude;
405+
406+
return point.latitude >= minX &&
407+
point.latitude <= maxX &&
408+
point.longitude >= minY &&
409+
point.longitude <= maxY;
410+
}
303411
}

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: geodesy
22
description: A Dart library for geodesic and trigonometric calculations working with points and paths
3-
version: 0.5.0
3+
version: 0.6.0
44
homepage: https://github.com/wingkwong/geodesy
55

66
environment:

test/geodesy_test.dart

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,4 +164,48 @@ void main() {
164164
});
165165
});
166166

167+
// Polygon Centroid
168+
169+
test('findPolygonCentroid calculates the centroid correctly', () {
170+
// Create a test polygon
171+
List<LatLng> polygon = [
172+
const LatLng(0, 0),
173+
const LatLng(0, 4),
174+
const LatLng(4, 4),
175+
const LatLng(4, 0),
176+
];
177+
178+
// Calculate the centroid
179+
LatLng centroid = geodesy.findPolygonCentroid(polygon);
180+
181+
// Verify the centroid coordinates
182+
expect(centroid.latitude, equals(2.0));
183+
expect(centroid.longitude, equals(2.0));
184+
});
185+
186+
// Polygon Intersection
187+
test('Intersection of two polygons', () {
188+
final polygon1 = [
189+
const LatLng(0, 0),
190+
const LatLng(0, 2),
191+
const LatLng(2, 2),
192+
const LatLng(2, 0),
193+
];
194+
195+
final polygon2 = [
196+
const LatLng(1, 1),
197+
const LatLng(1, 3),
198+
const LatLng(3, 3),
199+
const LatLng(3, 1),
200+
];
201+
202+
final intersectionPoints =
203+
geodesy.getPolygonIntersection(polygon1, polygon2);
204+
205+
expect(intersectionPoints.length, 2);
206+
expect(intersectionPoints[0].latitude, 1);
207+
expect(intersectionPoints[0].longitude, 2);
208+
expect(intersectionPoints[1].latitude, 2);
209+
expect(intersectionPoints[1].longitude, 1);
210+
});
167211
}

0 commit comments

Comments
 (0)