Skip to content
Merged
62 changes: 58 additions & 4 deletions lib/src/layer/polygon_layer/label.dart
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,64 @@ LatLng _computeLabelPosition(

/// Calculate the centroid of a given list of [LatLng] points.
LatLng _computeCentroid(List<LatLng> points) {
return LatLng(
points.map((e) => e.latitude).average,
points.map((e) => e.longitude).average,
);
if (points.isEmpty) {
throw ArgumentError('Polygon must contain at least one point');
}

if (points.length == 1) {
return points[0];
}

double signedArea = 0;
double centroidX = 0;
double centroidY = 0;

// For all vertices except last
for (int i = 0; i < points.length - 1; i++) {
final double x0 = points[i].longitude;
final double y0 = points[i].latitude;
final double x1 = points[i + 1].longitude;
final double y1 = points[i + 1].latitude;

// Calculate signed area contribution of current vertex
final double a = x0 * y1 - x1 * y0;
signedArea += a;

// Accumulate centroid components weighted by signed area
centroidX += (x0 + x1) * a;
centroidY += (y0 + y1) * a;
}

// Close the polygon by connecting last vertex to first
final double x0 = points.last.longitude;
final double y0 = points.last.latitude;
final double x1 = points.first.longitude;
final double y1 = points.first.latitude;
final double a = x0 * y1 - x1 * y0;
signedArea += a;
centroidX += (x0 + x1) * a;
centroidY += (y0 + y1) * a;

// Complete the signed area calculation
signedArea *= 0.5;

// Calculate centroid coordinates
centroidX /= 6 * signedArea;
centroidY /= 6 * signedArea;

// Handle special case of zero area (collinear points)
if (signedArea == 0) {
// Default to average of all points
double sumX = 0;
double sumY = 0;
for (final point in points) {
sumX += point.longitude;
sumY += point.latitude;
}
return LatLng(sumY / points.length, sumX / points.length);
}

return LatLng(centroidY, centroidX);
}

/// Calculate the centroid of a given list of [LatLng] points with multiple worlds.
Expand Down