@SqlNullable
    @Description("Returns the Point value that is the mathematical centroid of a Spherical Geography")
    @ScalarFunction("ST_Centroid")
    @SqlType(SPHERICAL_GEOGRAPHY_TYPE_NAME)
    public static Slice stSphericalCentroid(@SqlType(SPHERICAL_GEOGRAPHY_TYPE_NAME) Slice input)
    {
        OGCGeometry geometry = EsriGeometrySerde.deserialize(input);
        if (geometry.isEmpty()) {
            return null;
        }
        // TODO: add support for other types e.g. POLYGON
        validateSphericalType("ST_Centroid", geometry, EnumSet.of(POINT, MULTI_POINT));
        if (geometry instanceof OGCPoint) {
            return input;
        }

        OGCGeometryCollection geometryCollection = (OGCGeometryCollection) geometry;
        for (int i = 0; i < geometryCollection.numGeometries(); i++) {
            OGCGeometry g = geometryCollection.geometryN(i);
            validateSphericalType("ST_Centroid", g, EnumSet.of(POINT));
            Point p = (Point) g.getEsriGeometry();
            checkLongitude(p.getX());
            checkLatitude(p.getY());
        }

        Point centroid;
        if (geometryCollection.numGeometries() == 1) {
            centroid = (Point) geometryCollection.geometryN(0).getEsriGeometry();
        }
        else {
            double x3DTotal = 0;
            double y3DTotal = 0;
            double z3DTotal = 0;

            for (int i = 0; i < geometryCollection.numGeometries(); i++) {
                CartesianPoint cp = new CartesianPoint((Point) geometryCollection.geometryN(i).getEsriGeometry());
                x3DTotal += cp.getX();
                y3DTotal += cp.getY();
                z3DTotal += cp.getZ();
            }

            double centroidVectorLength = Math.sqrt(x3DTotal * x3DTotal + y3DTotal * y3DTotal + z3DTotal * z3DTotal);
            if (centroidVectorLength == 0.0) {
                throw new PrestoException(INVALID_FUNCTION_ARGUMENT, format("Unexpected error. Average vector length adds to zero (%f, %f, %f)", x3DTotal, y3DTotal, z3DTotal));
            }
            centroid = new CartesianPoint(
                    x3DTotal / centroidVectorLength,
                    y3DTotal / centroidVectorLength,
                    z3DTotal / centroidVectorLength).asSphericalPoint();
        }
        return EsriGeometrySerde.serialize(new OGCPoint(centroid, geometryCollection.getEsriSpatialReference()));
    }
@Test
    public void testSTSphericalCentroid()
    {
        // Spherical centroid testing
        assertSphericalCentroid("POINT (3 5)", new Point(3, 5));
        assertSphericalCentroid("POINT EMPTY", null);
        assertSphericalCentroid("MULTIPOINT EMPTY", null);
        assertSphericalCentroid("MULTIPOINT (3 5)", new Point(3, 5));
        assertSphericalCentroid("MULTIPOINT (0 -45, 0 45)", new Point(0, 0));
        assertSphericalCentroid("MULTIPOINT (45 0, -45 0)", new Point(0, 0));
        assertSphericalCentroid("MULTIPOINT (0 0, -180 0)", new Point(-90, 45));
        assertSphericalCentroid("MULTIPOINT (0 -45, 0 45, 30 0)", new Point(12.36780515862267, 0));
        assertSphericalCentroid("MULTIPOINT (0 -45, 0 45, 30 0, -30 0)", new Point(0, 0));
    }