Skip to content

Commit

Permalink
Merge pull request #26 from wingkwong/develop
Browse files Browse the repository at this point in the history
0.6.0
  • Loading branch information
wingkwong authored Jun 25, 2023
2 parents fed5832 + 1743e51 commit a7147f2
Show file tree
Hide file tree
Showing 7 changed files with 245 additions and 15 deletions.
11 changes: 8 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
# CHANGELOG

## 0.6.0

- Add findPolygonCentroid
- Add getPolygonIntersection

## 0.5.0
- greatCircleDistanceBetweenTwoGeoPoints
- getRectangleBounds
- calculateBoundingBox
- Add greatCircleDistanceBetweenTwoGeoPoints
- Add getRectangleBounds
- Add calculateBoundingBox

## 0.4.2
- Removed pedantic
Expand Down
54 changes: 47 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,18 +148,18 @@ Similar to PolygonEnvelop in Python
List<LatLng> rectangleBounds = geodesy.getRectangleBounds(polygonCoords);
```

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

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

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

### calculateBoundingBox(LatLng centerPoint, num distanceInKm)
Expand All @@ -174,3 +174,43 @@ Given the Latitude and Longitude and distance in kilometers it calculate the bou
final boundingBox = geodesy.calculateBoundingBox(centerPoint, distanceInKm);
```

## findPolygonCentroid(List<LatLng> polygon)

```dart
List<LatLng> polygon = [
const LatLng(0, 0),
const LatLng(4, 0),
const LatLng(4, 4),
const LatLng(0, 4)
];
LatLng centroid = geodesy.findPolygonCentroid(polygon);
print("Centroid: ${centroid.latitude}, ${centroid.longitude}");
```

## getPolygonIntersection(List<LatLng> polygon1, List<LatLng> polygon2)

```dart
final List<LatLng> polygon1 = [
const LatLng(0, 0),
const LatLng(0, 2),
const LatLng(2, 2),
const LatLng(2, 0),
];
final List<LatLng> polygon2 = [
const LatLng(1, 1),
const LatLng(1, 3),
const LatLng(3, 3),
const LatLng(3, 1),
];
final List<LatLng> intersectionPoints =
geodesy.getPolygonIntersection(polygon1, polygon2);
print('Intersection Points:');
for (final point in intersectionPoints) {
print('Latitude: ${point.latitude}, Longitude: ${point.longitude}');
}
```
3 changes: 0 additions & 3 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@
include: package:lints/core.yaml

analyzer:
strong-mode:
implicit-casts: false
implicit-dynamic: false
errors:
missing_return: error
missing_required_param: error
Expand Down
36 changes: 36 additions & 0 deletions example/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,40 @@ void main() async {
print('[calculateBoundingBox]: ');
print(' > Top Left: ${boundingBox[0]}');
print(' > Bottom Right: ${boundingBox[1]}');

// Polygon Centroid
List<LatLng> polygon = [
const LatLng(0, 0),
const LatLng(4, 0),
const LatLng(4, 4),
const LatLng(0, 4)
];

LatLng centroid = geodesy.findPolygonCentroid(polygon);

print("Centroid: ${centroid.latitude}, ${centroid.longitude}");

// Polygon Intersection

final List<LatLng> polygon1 = [
const LatLng(0, 0),
const LatLng(0, 2),
const LatLng(2, 2),
const LatLng(2, 0),
];

final List<LatLng> polygon2 = [
const LatLng(1, 1),
const LatLng(1, 3),
const LatLng(3, 3),
const LatLng(3, 1),
];

final List<LatLng> intersectionPoints =
geodesy.getPolygonIntersection(polygon1, polygon2);

print('Intersection Points:');
for (final point in intersectionPoints) {
print('Latitude: ${point.latitude}, Longitude: ${point.longitude}');
}
}
110 changes: 109 additions & 1 deletion lib/src/geodesy.dart
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,6 @@ class Geodesy {
}

/// GetRectangleBounds
List<LatLng> getRectangleBounds(List<LatLng> polygonCoords) {
num minLatitude = double.infinity.toDouble();
num maxLatitude = double.negativeInfinity.toDouble();
Expand Down Expand Up @@ -300,4 +299,113 @@ class Geodesy {
LatLng(bottomLat.toDouble(), rightLng.toDouble());
return [topLeft, bottomRight];
}

/// finds the centroid of polygons
LatLng findPolygonCentroid(List<LatLng> polygons) {
num x = 0;
num y = 0;
num signedArea = 0;

num vertexCount = polygons.length;

for (int i = 0; i < vertexCount; i++) {
final LatLng currentVertex = polygons[i];
final LatLng nextVertex = polygons[(i + 1) % vertexCount.toInt()];

num a = currentVertex.longitude * nextVertex.latitude -
nextVertex.longitude * currentVertex.latitude;
signedArea += a;
x += (currentVertex.longitude + nextVertex.longitude) * a;
y += (currentVertex.latitude + nextVertex.latitude) * a;
}

signedArea *= 0.5;
x /= (6 * signedArea);
y /= (6 * signedArea);

// Return the centroid as LatLng object
return LatLng(
y.toDouble(),
x.toDouble(),
);
}

/// Polygon Intersection
List<LatLng> getPolygonIntersection(
List<LatLng> polygon1, List<LatLng> polygon2) {
final List<LatLng> intersectionPoints = <LatLng>[];

for (int i = 0; i < polygon1.length; i++) {
final int j = (i + 1) % polygon1.length;
final LatLng edge1Start = polygon1[i];
final LatLng edge1End = polygon1[j];

for (int k = 0; k < polygon2.length; k++) {
final int l = (k + 1) % polygon2.length;
final LatLng edge2Start = polygon2[k];
final LatLng edge2End = polygon2[l];

final LatLng? intersection =
_getLineIntersection(edge1Start, edge1End, edge2Start, edge2End);
if (intersection != null) {
intersectionPoints.add(intersection);
}
}
}
return intersectionPoints;
}

LatLng? _getLineIntersection(
LatLng start1, LatLng end1, LatLng start2, LatLng end2) {
final num x1 = start1.latitude;
final num y1 = start1.longitude;
final num x2 = end1.latitude;
final num y2 = end1.longitude;
final num x3 = start2.latitude;
final num y3 = start2.longitude;
final num x4 = end2.latitude;
final num y4 = end2.longitude;

final num denominator = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
if (denominator == 0) {
return null; // Lines are parallel or coincident
}

final num intersectionX =
((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) /
denominator;
final num intersectionY =
((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) /
denominator;

final LatLng intersection =
LatLng(intersectionX.toDouble(), intersectionY.toDouble());

if (_isPointOnLine(intersection, start1, end1) &&
_isPointOnLine(intersection, start2, end2)) {
return intersection;
} else {
return null;
}
}

bool _isPointOnLine(LatLng point, LatLng lineStart, LatLng lineEnd) {
final minX = lineStart.latitude < lineEnd.latitude
? lineStart.latitude
: lineEnd.latitude;
final maxX = lineStart.latitude > lineEnd.latitude
? lineStart.latitude
: lineEnd.latitude;
final minY = lineStart.longitude < lineEnd.longitude
? lineStart.longitude
: lineEnd.longitude;
final maxY = lineStart.longitude > lineEnd.longitude
? lineStart.longitude
: lineEnd.longitude;

return point.latitude >= minX &&
point.latitude <= maxX &&
point.longitude >= minY &&
point.longitude <= maxY;
}
}
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: geodesy
description: A Dart library for geodesic and trigonometric calculations working with points and paths
version: 0.5.0
version: 0.6.0
homepage: https://github.com/wingkwong/geodesy

environment:
Expand Down
44 changes: 44 additions & 0 deletions test/geodesy_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -164,4 +164,48 @@ void main() {
});
});

// Polygon Centroid

test('findPolygonCentroid calculates the centroid correctly', () {
// Create a test polygon
List<LatLng> polygon = [
const LatLng(0, 0),
const LatLng(0, 4),
const LatLng(4, 4),
const LatLng(4, 0),
];

// Calculate the centroid
LatLng centroid = geodesy.findPolygonCentroid(polygon);

// Verify the centroid coordinates
expect(centroid.latitude, equals(2.0));
expect(centroid.longitude, equals(2.0));
});

// Polygon Intersection
test('Intersection of two polygons', () {
final polygon1 = [
const LatLng(0, 0),
const LatLng(0, 2),
const LatLng(2, 2),
const LatLng(2, 0),
];

final polygon2 = [
const LatLng(1, 1),
const LatLng(1, 3),
const LatLng(3, 3),
const LatLng(3, 1),
];

final intersectionPoints =
geodesy.getPolygonIntersection(polygon1, polygon2);

expect(intersectionPoints.length, 2);
expect(intersectionPoints[0].latitude, 1);
expect(intersectionPoints[0].longitude, 2);
expect(intersectionPoints[1].latitude, 2);
expect(intersectionPoints[1].longitude, 1);
});
}

0 comments on commit a7147f2

Please sign in to comment.