From: Paul Ramsey Date: Wed, 14 Nov 2012 20:45:16 +0000 (+0000) Subject: #799, make geographic coordinates in range X-Git-Tag: 2.1.0beta2~399 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f6580e93a137282691647929c93536e7c8ddccd6;p=postgis #799, make geographic coordinates in range git-svn-id: http://svn.osgeo.org/postgis/trunk@10670 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/liblwgeom/liblwgeom.h.in b/liblwgeom/liblwgeom.h.in index 61e26bae3..35b3d38fb 100644 --- a/liblwgeom/liblwgeom.h.in +++ b/liblwgeom/liblwgeom.h.in @@ -1243,6 +1243,11 @@ extern double lwpoint_get_m(const LWPOINT *point); */ extern int32_t lwgeom_get_srid(const LWGEOM *geom); +/** +* Return LWTYPE number +*/ +extern uint32_t lwgeom_get_type(const LWGEOM *geom); + /** * Return #LW_TRUE if geometry has Z ordinates */ @@ -1469,15 +1474,20 @@ extern char* gserialized_to_string(const GSERIALIZED *g); extern GSERIALIZED* gserialized_copy(const GSERIALIZED *g); /** -* Check that coordinates of LWGEOM are all within the geodetic range. +* Check that coordinates of LWGEOM are all within the geodetic range (-180, -90, 180, 90) */ extern int lwgeom_check_geodetic(const LWGEOM *geom); /** -* Check that coordinates of LWGEOM are all within the geodetic range. +* Gently move coordinates of LWGEOM if they are close enough into geodetic range. */ extern int lwgeom_nudge_geodetic(LWGEOM *geom); +/** +* Force coordinates of LWGEOM into geodetic range (-180, -90, 180, 90) +*/ +extern int lwgeom_force_geodetic(LWGEOM *geom); + /** * Set the FLAGS geodetic bit on geometry an all sub-geometries and pointlists */ diff --git a/liblwgeom/lwgeodetic.c b/liblwgeom/lwgeodetic.c index ebc77b9eb..c79023991 100644 --- a/liblwgeom/lwgeodetic.c +++ b/liblwgeom/lwgeodetic.c @@ -2709,6 +2709,90 @@ int lwgeom_check_geodetic(const LWGEOM *geom) return LW_FALSE; } +static int ptarray_force_geodetic(POINTARRAY *pa) +{ + int t; + int changed = LW_FALSE; + POINT4D pt; + + assert(pa); + + for ( t=0; t < pa->npoints; t++ ) + { + getPoint4d_p(pa, t, &pt); + if ( pt.x < -180.0 || pt.x > 180.0 || pt.y < -90.0 || pt.y > 90.0 ) + { + pt.x = longitude_degrees_normalize(pt.x); + pt.y = latitude_degrees_normalize(pt.y); + ptarray_set_point4d(pa, t, &pt); + changed = LW_TRUE; + } + } + return changed; +} + +static int lwpoint_force_geodetic(LWPOINT *point) +{ + assert(point); + return ptarray_force_geodetic(point->point); +} + +static int lwline_force_geodetic(LWLINE *line) +{ + assert(line); + return ptarray_force_geodetic(line->points); +} + +static int lwpoly_force_geodetic(LWPOLY *poly) +{ + int i = 0; + int changed = LW_FALSE; + assert(poly); + + for ( i = 0; i < poly->nrings; i++ ) + { + if ( ptarray_force_geodetic(poly->rings[i]) == LW_TRUE ) + changed = LW_TRUE; + } + return changed; +} + +static int lwcollection_force_geodetic(LWCOLLECTION *col) +{ + int i = 0; + int changed = LW_FALSE; + assert(col); + + for ( i = 0; i < col->ngeoms; i++ ) + { + if ( lwgeom_force_geodetic(col->geoms[i]) == LW_TRUE ) + changed = LW_TRUE; + } + return changed; +} + +int lwgeom_force_geodetic(LWGEOM *geom) +{ + switch ( lwgeom_get_type(geom) ) + { + case POINTTYPE: + return lwpoint_force_geodetic((LWPOINT *)geom); + case LINETYPE: + return lwline_force_geodetic((LWLINE *)geom); + case POLYGONTYPE: + return lwpoly_force_geodetic((LWPOLY *)geom); + case MULTIPOINTTYPE: + case MULTILINETYPE: + case MULTIPOLYGONTYPE: + case COLLECTIONTYPE: + return lwcollection_force_geodetic((LWCOLLECTION *)geom); + default: + lwerror("unsupported input geometry type: %d", lwgeom_get_type(geom)); + } + return LW_FALSE; +} + + double ptarray_length_spheroid(const POINTARRAY *pa, const SPHEROID *s) { GEOGRAPHIC_POINT a, b; diff --git a/liblwgeom/lwgeom.c b/liblwgeom/lwgeom.c index ddfd917f6..4d4ccbef2 100644 --- a/liblwgeom/lwgeom.c +++ b/liblwgeom/lwgeom.c @@ -713,6 +713,13 @@ lwgeom_get_srid(const LWGEOM *geom) return geom->srid; } +uint32_t +lwgeom_get_type(const LWGEOM *geom) +{ + if ( ! geom ) return 0; + return geom->type; +} + int lwgeom_has_z(const LWGEOM *geom) { diff --git a/postgis/geography_inout.c b/postgis/geography_inout.c index bde305ac3..95e6b45c3 100644 --- a/postgis/geography_inout.c +++ b/postgis/geography_inout.c @@ -85,15 +85,12 @@ GSERIALIZED* gserialized_geography_from_lwgeom(LWGEOM *lwgeom, int32 geog_typmod /* Check that this is a type we can handle */ geography_valid_type(lwgeom->type); - /* Check that the coordinates are in range */ - if ( lwgeom_check_geodetic(lwgeom) == LW_FALSE ) + /* Force the geometry to have valid geodetic coordinate range. */ + if ( lwgeom_force_geodetic(lwgeom) == LW_TRUE ) { - if ( (! lwgeom_nudge_geodetic(lwgeom)) || lwgeom_check_geodetic(lwgeom) == LW_FALSE ) - { - ereport(ERROR, ( - errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("Coordinate values are out of range [-180 -90, 180 90] for GEOGRAPHY type" ))); - } + ereport(NOTICE, ( + errmsg_internal("Coordinate values were coerced into range [-180 -90, 180 90] for GEOGRAPHY" )) + ); } /* Force default SRID to the default */ @@ -589,15 +586,12 @@ Datum geography_from_geometry(PG_FUNCTION_ARGS) /* Error on any SRID != default */ srid_is_latlong(fcinfo, lwgeom->srid); - /* Check if the geography has valid coordinate range. */ - if ( lwgeom_check_geodetic(lwgeom) == LW_FALSE ) + /* Force the geometry to have valid geodetic coordinate range. */ + if ( lwgeom_force_geodetic(lwgeom) == LW_TRUE ) { - if ( (! lwgeom_nudge_geodetic(lwgeom)) || lwgeom_check_geodetic(lwgeom) == LW_FALSE ) - { - ereport(ERROR, ( - errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("Coordinate values are out of range [-180 -90, 180 90] for GEOGRAPHY type" ))); - } + ereport(NOTICE, ( + errmsg_internal("Coordinate values were coerced into range [-180 -90, 180 90] for GEOGRAPHY" )) + ); } /* diff --git a/regress/tickets_expected b/regress/tickets_expected index f31d025df..72b195432 100644 --- a/regress/tickets_expected +++ b/regress/tickets_expected @@ -197,6 +197,7 @@ ERROR: MultiSurface cannot contain MultiPoint element at character 8 ERROR: AddToPROJ4SRSCache: could not parse proj4 string '' #1038| #1042|2 +NOTICE: Coordinate values were coerced into range [-180 -90, 180 90] for GEOGRAPHY #1170|90 #1264|t #1398a|POINT(-119.093153 45.632669)