centerOfMass function

Feature<Point> centerOfMass(
  1. GeoJSONObject geoJson, {
  2. Map<String, dynamic>? properties = const {},
})

Computes the center of mass of any GeoJSON object and returns it as a Feature<Point>.

Handles the following geometry types:

  • Point: returns the point itself.

  • LineString: returns the average of its vertices.

  • Polygon: uses the geometric centroid formula weighted by area.

  • MultiPolygon: computes a weighted average of each polygon's center of mass by area.

  • All other types: falls back to centroid.

  • geoJson the GeoJSON object to compute the center of mass for.

  • properties optional properties to attach to the returned Feature.

Implementation

Feature<Point> centerOfMass(
  GeoJSONObject geoJson, {
  Map<String, dynamic>? properties = const {},
}) {
  GeometryObject? geometry;

  if (geoJson is Feature) {
    geometry = geoJson.geometry;
  } else if (geoJson is GeometryObject) {
    geometry = geoJson;
  } else {
    return centroid(geoJson);
  }

  if (geometry is Point) {
    return Feature<Point>(
      geometry: Point(coordinates: geometry.coordinates),
      properties: properties,
    );
  }

  if (geometry is LineString) {
    // line center = average of vertices
    final coords = geometry.coordinates;
    final n = coords.length;
    double sx = 0, sy = 0;
    for (final p in coords) {
      sx += p.lng;
      sy += p.lat;
    }
    return Feature<Point>(
      geometry: Point(coordinates: Position(sx / n, sy / n)),
      properties: properties,
    );
  }

  if (geometry is Polygon) {
    return _centerOfMassPolygon(geometry, properties: properties);
  }

  if (geometry is MultiPolygon) {
    double totalArea = 0.0;
    double sx = 0.0;
    double sy = 0.0;

    for (final polygonCoords in geometry.coordinates) {
      final poly = Polygon(coordinates: polygonCoords);
      final comFeature = _centerOfMassPolygon(poly, properties: properties);
      final com = comFeature.geometry!.coordinates;

      // Compute polygon area
      final area = _polygonArea(polygonCoords.first);
      totalArea += area;

      sx += com.lng * area;
      sy += com.lat * area;
    }

    if (totalArea == 0) {
      // all polygons degenerate -> average of all vertices
      final allVerts = geometry.coordinates.expand((p) => p.first).toList();
      final n = allVerts.length;
      double ax = 0, ay = 0;
      for (final v in allVerts) {
        ax += v.lng;
        ay += v.lat;
      }
      return Feature<Point>(
        geometry: Point(coordinates: Position(ax / n, ay / n)),
        properties: properties,
      );
    }

    final center = Position(sx / totalArea, sy / totalArea);
    return Feature<Point>(
      geometry: Point(coordinates: center),
      properties: properties,
    );
  }

  // fallback
  return centroid(geoJson);
}