From: Paul Ramsey Date: Fri, 17 Jun 2011 21:11:05 +0000 (+0000) Subject: Define alias ST_Perimeter (for geography ST_Length) (#526) X-Git-Tag: 2.0.0alpha1~1412 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ade9d75792b340ea1eab0fe94a3f09253b3910a9;p=postgis Define alias ST_Perimeter (for geography ST_Length) (#526) git-svn-id: http://svn.osgeo.org/postgis/trunk@7414 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/postgis/geography.sql.in.c b/postgis/geography.sql.in.c index b860a5c4b..2b1431c65 100644 --- a/postgis/geography.sql.in.c +++ b/postgis/geography.sql.in.c @@ -658,6 +658,21 @@ CREATE OR REPLACE FUNCTION ST_Length(text) $$ SELECT ST_Length($1::geometry); $$ LANGUAGE 'SQL' IMMUTABLE STRICT; + +-- Availability: 2.0.0 +CREATE OR REPLACE FUNCTION ST_Perimeter(geography, boolean) + RETURNS float8 + AS 'MODULE_PATHNAME','geography_perimeter' + LANGUAGE 'C' IMMUTABLE STRICT + COST 100; + +-- Availability: 2.0.0 +CREATE OR REPLACE FUNCTION ST_Perimeter(geography) + RETURNS float8 + AS 'SELECT ST_Perimeter($1, true)' + LANGUAGE 'SQL' IMMUTABLE; + + -- Availability: 1.5.0 CREATE OR REPLACE FUNCTION _ST_PointOutside(geography) RETURNS geography diff --git a/postgis/geography_measurement.c b/postgis/geography_measurement.c index 30b5bd86c..9ea6d2bae 100644 --- a/postgis/geography_measurement.c +++ b/postgis/geography_measurement.c @@ -268,9 +268,68 @@ Datum geography_area(PG_FUNCTION_ARGS) } +/* +** geography_perimeter(GSERIALIZED *g) +** returns double perimeter in meters for area features +*/ +PG_FUNCTION_INFO_V1(geography_perimeter); +Datum geography_perimeter(PG_FUNCTION_ARGS) +{ + LWGEOM *lwgeom = NULL; + GSERIALIZED *g = NULL; + double length; + bool use_spheroid = LW_TRUE; + SPHEROID s; + int type; + + /* Get our geometry object loaded into memory. */ + g = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + + /* Only return for area features. */ + type = gserialized_get_type(g); + if ( ! (type == POLYGONTYPE || type == MULTIPOLYGONTYPE || type == COLLECTIONTYPE) ) + { + PG_RETURN_FLOAT8(0.0); + } + + lwgeom = lwgeom_from_gserialized(g); + + /* EMPTY things have no perimeter */ + if ( lwgeom_is_empty(lwgeom) ) + { + lwgeom_free(lwgeom); + PG_RETURN_FLOAT8(0.0); + } + + /* Read our calculation type */ + use_spheroid = PG_GETARG_BOOL(1); + + /* Initialize spheroid */ + spheroid_init(&s, WGS84_MAJOR_AXIS, WGS84_MINOR_AXIS); + + /* User requests spherical calculation, turn our spheroid into a sphere */ + if ( ! use_spheroid ) + s.a = s.b = s.radius; + + /* Calculate the length */ + length = lwgeom_length_spheroid(lwgeom, &s); + + /* Something went wrong... */ + if ( length < 0.0 ) + { + elog(ERROR, "lwgeom_length_spheroid returned length < 0.0"); + PG_RETURN_NULL(); + } + + /* Clean up, but not all the way to the point arrays */ + lwgeom_free(lwgeom); + + PG_FREE_IF_COPY(g, 0); + PG_RETURN_FLOAT8(length); +} /* -** geography_length_sphere(GSERIALIZED *g) +** geography_length(GSERIALIZED *g) ** returns double length in meters */ PG_FUNCTION_INFO_V1(geography_length); @@ -287,7 +346,7 @@ Datum geography_length(PG_FUNCTION_ARGS) lwgeom = lwgeom_from_gserialized(g); /* EMPTY things have no length */ - if ( lwgeom_is_empty(lwgeom) ) + if ( lwgeom_is_empty(lwgeom) || lwgeom->type == POLYGONTYPE || lwgeom->type == MULTIPOLYGONTYPE ) { lwgeom_free(lwgeom); PG_RETURN_FLOAT8(0.0); @@ -309,12 +368,12 @@ Datum geography_length(PG_FUNCTION_ARGS) /* Something went wrong... */ if ( length < 0.0 ) { - elog(ERROR, "geography_length_sphere returned length < 0.0"); + elog(ERROR, "lwgeom_length_spheroid returned length < 0.0"); PG_RETURN_NULL(); } - /* Clean up, but not all the way to the point arrays */ - lwgeom_release(lwgeom); + /* Clean up */ + lwgeom_free(lwgeom); PG_FREE_IF_COPY(g, 0); PG_RETURN_FLOAT8(length);