]> granicus.if.org Git - postgis/commitdiff
#799, make geographic coordinates in range
authorPaul Ramsey <pramsey@cleverelephant.ca>
Wed, 14 Nov 2012 20:45:16 +0000 (20:45 +0000)
committerPaul Ramsey <pramsey@cleverelephant.ca>
Wed, 14 Nov 2012 20:45:16 +0000 (20:45 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@10670 b70326c6-7e19-0410-871a-916f4a2858ee

liblwgeom/liblwgeom.h.in
liblwgeom/lwgeodetic.c
liblwgeom/lwgeom.c
postgis/geography_inout.c
regress/tickets_expected

index 61e26bae324023f422615dbb9821e94ef16f5aab..35b3d38fb3ca27e55dd85edf769d3dbd7aca9b10 100644 (file)
@@ -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
 */
index ebc77b9eb24a5ac40c7f8c287322d532f5e02b81..c790239917d94dd799aceebe0d72d322ea0453e6 100644 (file)
@@ -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;
index ddfd917f6b2a2fe7ff1ec84b86b8e04c6de1f83a..4d4ccbef253abb73b3eb5c81a73fd3600c7ba922 100644 (file)
@@ -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)
 {
index bde305ac3eac38ae8e5a8d208fc85f38f3fba4b3..95e6b45c3365896b06a0bf1266751116aa553fd1 100644 (file)
@@ -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" ))
+               );
        }
 
        /*
index f31d025df02dff47aca703fd31929589672315d2..72b195432b3b3b794a320700bccdb9d9f74f3d4d 100644 (file)
@@ -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)