]> granicus.if.org Git - postgis/commitdiff
ST_SnapToGrid returns a value out of range (#1292)
authorPaul Ramsey <pramsey@cleverelephant.ca>
Tue, 31 Jan 2012 18:19:36 +0000 (18:19 +0000)
committerPaul Ramsey <pramsey@cleverelephant.ca>
Tue, 31 Jan 2012 18:19:36 +0000 (18:19 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@8980 b70326c6-7e19-0410-871a-916f4a2858ee

liblwgeom/liblwgeom.h.in
liblwgeom/lwgeodetic.c
postgis/geography_inout.c

index c8d226f6c690ba6b6a029f55e48ef8275b00fa7e..ce1fcdfe14d160682a5c3871dde0fa650f4a4331 100644 (file)
@@ -1437,6 +1437,11 @@ extern GSERIALIZED* gserialized_copy(const GSERIALIZED *g);
 */
 extern int lwgeom_check_geodetic(const LWGEOM *geom);
 
+/**
+* Check that coordinates of LWGEOM are all within the geodetic range.
+*/
+extern int lwgeom_nudge_geodetic(LWGEOM *geom);
+
 /**
 * Set the FLAGS geodetic bit on geometry an all sub-geometries and pointlists
 */
index 83d7db663a4588987679b49184fd029b2c568d9c..0db9d4893ebb54bc4516da69397c5fc735da4b10 100644 (file)
@@ -2653,3 +2653,104 @@ double lwgeom_length_spheroid(const LWGEOM *geom, const SPHEROID *s)
        lwerror("unsupported type passed to lwgeom_length_sphere");
        return 0.0;
 }
+
+/**
+* When features are snapped or sometimes they are just this way, they are very close to 
+* the geodetic bounds but slightly over. This routine nudges those points, and only
+* those points, back over to the bounds.
+* http://trac.osgeo.org/postgis/ticket/1292
+*/
+int ptarray_nudge_geodetic(POINTARRAY *pa)
+{
+       int i;
+       POINT4D p;
+       int altered = LW_FALSE;
+       int rv = LW_FALSE;
+       static double tolerance = 1e-10;
+       if ( ! pa ) return;
+       for(i = 0; i < pa->npoints; i++ )
+       {
+               getPoint4d_p(pa, i, &p);
+               if ( p.x < -180.0 && (-180.0 - p.x < tolerance) )
+               {
+                       p.x = -180.0;
+                       altered = LW_TRUE;
+               }
+               else if ( p.x > 180.0 && (p.x - 180.0 < tolerance) )
+               {
+                       p.x = 180.0;
+                       altered = LW_TRUE;
+               }
+               else if ( p.y < -90.0 && (-90.0 - p.y < tolerance) )
+               {
+                       p.y = -90.0;
+                       altered = LW_TRUE;
+               }
+               else if ( p.y > 90.0 && (p.y - 90.0 < tolerance) )
+               {
+                       p.y = 90.0;
+                       altered = LW_TRUE;
+               }
+               if ( altered == LW_TRUE )
+               {
+                       ptarray_set_point4d(pa, i, &p);
+                       altered = LW_FALSE;
+                       rv = LW_TRUE;
+               }
+       }
+       return rv;
+}
+
+/**
+* When features are snapped or sometimes they are just this way, they are very close to 
+* the geodetic bounds but slightly over. This routine nudges those points, and only
+* those points, back over to the bounds.
+* http://trac.osgeo.org/postgis/ticket/1292
+*/
+int lwgeom_nudge_geodetic(LWGEOM *geom)
+{
+       int type;
+       int i = 0;
+       int rv = LW_FALSE;
+
+       assert(geom);
+
+       /* No points in nothing */
+       if ( lwgeom_is_empty(geom) )
+               return LW_FALSE;
+
+       type = geom->type;
+
+       if ( type == POINTTYPE )
+               return ptarray_nudge_geodetic(((LWPOINT*)geom)->point);
+
+       if ( type == LINETYPE )
+               return ptarray_nudge_geodetic(((LWLINE*)geom)->points);
+
+       if ( type == POLYGONTYPE )
+       {
+               LWPOLY *poly = (LWPOLY*)geom;
+               for ( i = 0; i < poly->nrings; i++ )
+               {
+                       rv = (rv == LW_TRUE ? rv : ptarray_nudge_geodetic(poly->rings[i]));
+               }
+               return rv;
+       }
+
+       if ( type == TRIANGLETYPE )
+               return ptarray_nudge_geodetic(((LWTRIANGLE*)geom)->points);
+
+       if ( lwtype_is_collection( type ) )
+       {
+               LWCOLLECTION *col = (LWCOLLECTION*)geom;
+
+               for ( i = 0; i < col->ngeoms; i++ )
+               {
+                       rv = (rv == LW_TRUE ? rv : ptarray_nudge_geodetic(col->geoms[i]));
+               }
+               return rv;
+       }
+
+       lwerror("unsupported type (%s) passed to lwgeom_nudge_geodetic", lwtype_name(type));
+       return rv;
+}
\ No newline at end of file
index f710dc41627a8e7df7252fb059538e9b43c19f17..d121a4b213fbd6b2e1d39f819bde0ef6750c6751 100644 (file)
@@ -87,9 +87,12 @@ GSERIALIZED* gserialized_geography_from_lwgeom(LWGEOM *lwgeom, int32 geog_typmod
        /* Check that the coordinates are in range */
        if ( 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" )));
+               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" )));
+               }
        }
 
        /* Force default SRID to the default */
@@ -562,9 +565,12 @@ Datum geography_from_geometry(PG_FUNCTION_ARGS)
        /* Check if the geography has valid coordinate range. */
        if ( 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" )));
+               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" )));
+               }
        }
 
        /*