106 lines
2.2 KiB
Dart
106 lines
2.2 KiB
Dart
|
|
import 'dart:math';
|
||
|
|
|
||
|
|
import 'package:latlong2/latlong.dart';
|
||
|
|
|
||
|
|
class GeometryMeasure {
|
||
|
|
static final Distance _distance = const Distance();
|
||
|
|
|
||
|
|
static double lineLengthMeters(List<LatLng> points) {
|
||
|
|
if (points.length < 2) return 0.0;
|
||
|
|
|
||
|
|
double sum = 0.0;
|
||
|
|
|
||
|
|
for (var i = 1; i < points.length; i++) {
|
||
|
|
sum += _distance.as(
|
||
|
|
LengthUnit.Meter,
|
||
|
|
points[i - 1],
|
||
|
|
points[i],
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
return sum;
|
||
|
|
}
|
||
|
|
|
||
|
|
static double polygonAreaSquareMeters(List<LatLng> points) {
|
||
|
|
final polygon = _normalizedPolygon(points);
|
||
|
|
|
||
|
|
if (polygon.length < 3) return 0.0;
|
||
|
|
|
||
|
|
final origin = _centroid(polygon);
|
||
|
|
final projected =
|
||
|
|
polygon.map((p) => _projectToLocalMeters(p, origin)).toList();
|
||
|
|
|
||
|
|
double area = 0.0;
|
||
|
|
|
||
|
|
for (var i = 0; i < projected.length; i++) {
|
||
|
|
final j = (i + 1) % projected.length;
|
||
|
|
|
||
|
|
area += projected[i].x * projected[j].y - projected[j].x * projected[i].y;
|
||
|
|
}
|
||
|
|
|
||
|
|
return area.abs() / 2.0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static List<LatLng> _normalizedPolygon(List<LatLng> source) {
|
||
|
|
final points = List<LatLng>.from(source);
|
||
|
|
|
||
|
|
if (points.length < 2) return points;
|
||
|
|
|
||
|
|
final first = points.first;
|
||
|
|
final last = points.last;
|
||
|
|
|
||
|
|
final closeDistance = _distance.as(
|
||
|
|
LengthUnit.Meter,
|
||
|
|
first,
|
||
|
|
last,
|
||
|
|
);
|
||
|
|
|
||
|
|
if (closeDistance < 0.01) {
|
||
|
|
points.removeLast();
|
||
|
|
}
|
||
|
|
|
||
|
|
return points;
|
||
|
|
}
|
||
|
|
|
||
|
|
static LatLng _centroid(List<LatLng> points) {
|
||
|
|
double lat = 0.0;
|
||
|
|
double lon = 0.0;
|
||
|
|
|
||
|
|
for (final p in points) {
|
||
|
|
lat += p.latitude;
|
||
|
|
lon += p.longitude;
|
||
|
|
}
|
||
|
|
|
||
|
|
return LatLng(
|
||
|
|
lat / points.length,
|
||
|
|
lon / points.length,
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
static _Point2D _projectToLocalMeters(
|
||
|
|
LatLng point,
|
||
|
|
LatLng origin,
|
||
|
|
) {
|
||
|
|
const earthRadius = 6378137.0;
|
||
|
|
|
||
|
|
final latRad = point.latitude * pi / 180.0;
|
||
|
|
final lonRad = point.longitude * pi / 180.0;
|
||
|
|
|
||
|
|
final originLatRad = origin.latitude * pi / 180.0;
|
||
|
|
final originLonRad = origin.longitude * pi / 180.0;
|
||
|
|
|
||
|
|
final x = earthRadius * (lonRad - originLonRad) * cos(originLatRad);
|
||
|
|
|
||
|
|
final y = earthRadius * (latRad - originLatRad);
|
||
|
|
|
||
|
|
return _Point2D(x, y);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
class _Point2D {
|
||
|
|
final double x;
|
||
|
|
final double y;
|
||
|
|
|
||
|
|
const _Point2D(this.x, this.y);
|
||
|
|
}
|