2

I am trying to get the center of a shape in android. The shape is draw by hand on the map. I have all of the co-ordinates but the mean values are turning out to be trickier than I thought. I want to plot a marker on the mean latitude and longitude.

I have tried summing up the latitude and longitude separately and then dividing by the number of points. This does not give the correct answer. The marker always seems to be trailing behind the draw figure. I have also tried using the implementation but it gives the same answer, a previous SO question, Calculate the center point of multiple latitude/longitude coordinate pairs

The code I have been using:

private void calculateFreeHandPolygonParameters(){

    double xValues = 0;
    double yValues = 0;
    double zValues = 0;
    int count = 0;

    // linesForPolygon a list of the lines in the polygon
    for(Polyline line : linesForPolygon){
        for (LatLng point : line.getPoints()) {
            xValues += Math.cos(Math.toRadians(point.latitude)) * Math.cos(Math.toRadians(point.longitude));
            yValues += Math.cos(Math.toRadians(point.latitude)) * Math.sin(Math.toRadians(point.longitude));
            zValues += Math.sin(Math.toRadians(point.latitude));
            count++;
        }
    }

    double meanX = xValues/count;
    double meanY = yValues/count;
    double meanZ = zValues/count;

    double centralLongitude = Math.atan2(meanY, meanX);
    double centralSquareRoot = Math.sqrt(Math.pow(meanX, 2) + Math.pow(meanX, 2) + Math.pow(meanX, 2));
    double centralLatitude = Math.atan2(meanZ, centralSquareRoot);

    double latitude = Math.toDegrees(centralLatitude);
    double longitude = Math.toDegrees(centralLongitude);

    Log.i("MAPS", "Freehand Parameters: x mean -> " + latitude + " y mean -> " + longitude);

    testMarker = mMap.addMarker(new MarkerOptions()
            .position(new LatLng(latitude, longitude))
            .title("Polygon center")
            .snippet("lat: " + latitude + " long: " + longitude));
}
Community
  • 1
  • 1
  • The method you describe should work except perhaps in cases where the longitude is near the international dateline, or if the locations are near the poles. Perhaps you should share your code. – JerryM Apr 21 '16 at 21:03

2 Answers2

1
  1. You actually need to calculate what is called CENTROID. It's not a trivial thing, look here: http://www.spatialanalysisonline.com/HTML/index.html?centroids_and_centers.htm
  2. Pay attention to what is called GREAT CIRCLE, recall flight plans on an airplane maps... Thus if the distances are relatively large, you need to bare in mind this phenomena.
  3. This is a classic GIS question, after you understand the pseudo code of the algorithm, it's simple coding task... try gis.stackexchange.com
michael
  • 3,835
  • 14
  • 53
  • 90
  • How come the code I have been using does not work? It makes perfect sense to calculate the average like I have done? The first method in the link you gave is what I tried initially but kept trailing behind too. The method which require the area to be calculated will become extremely complicated – Michael Richardson Apr 21 '16 at 21:26
  • Yes, the low level code of this kind of algorithms indeed complicated... Usually one use gis library for this kind of task, or if the locations stored in data base with postgis, so postgis has this kind of query methods too. – michael Apr 21 '16 at 21:58
1

Here is my centroid code:

public class PolygonCentroid {

    private List<GeoPoint> points;
    private int pointsSize;

    public PolygonCentroid(List<GeoPoint> points) {
        this.points = points;
        this.pointsSize = points.size();
    }

    protected double polygonArea() {
        double area = 0;
        for (int i = 0, j; i < pointsSize; i++) {
            j = (i + 1) % pointsSize;
            area += points.get(i).getLongitude() * points.get(j).getLatitude();
            area -= points.get(i).getLatitude() * points.get(j).getLongitude();
        }
        area /= 2.0;
        return area;
    }

    public GeoPoint centroid() {
        double cx = 0, cy = 0;
        double factor;
        for (int i = 0, j; i < pointsSize; i++) {
            j = (i + 1) % pointsSize;
            factor = (points.get(i).getLongitude() * points.get(j).getLatitude() - points.get(j).getLongitude() * points.get(i).getLatitude());
            cx += (points.get(i).getLongitude() + points.get(j).getLongitude()) * factor;
            cy += (points.get(i).getLatitude() + points.get(j).getLatitude()) * factor;
        }
        double A = polygonArea();
        factor = 1.0 / (6.0 * A);
        cx *= factor;
        cy *= factor;
        return new GeoPoint(cy, cx);
    }

}

enter image description here

Also, please pay attention that the centroid can be outside of the polygon:

enter image description here

Full source code and usage.

Mikalai Daronin
  • 8,590
  • 2
  • 35
  • 47
  • This method works but only for the first iteration. I haven't figured out why it doesn't work if I draw another polygon. The marker trails behind as in the previous version of my code. – Michael Richardson Apr 22 '16 at 07:44
  • Don't forget to reset the list of co-ordinates like I did. – Michael Richardson Apr 22 '16 at 07:50
  • >"marker trails behind" I guess you should pay attention to [Z-ordering](https://stackoverflow.com/questions/14771569/google-maps-v2-marker-zordering-set-to-top), if you want to show some of your overlays on top always. – Mikalai Daronin Apr 22 '16 at 08:09