]> granicus.if.org Git - postgis/commitdiff
Fix EMPTY ~= EMPTY to return TRUE (#1453)
authorSandro Santilli <strk@keybit.net>
Wed, 11 Jan 2012 17:18:27 +0000 (17:18 +0000)
committerSandro Santilli <strk@keybit.net>
Wed, 11 Jan 2012 17:18:27 +0000 (17:18 +0000)
This also fixes ST_OrderingEquals for empty geometries and
adds the concept of NULL boxes to represent EMPTY boxes.

ST_Equals is still broken as it uses the overlap operator instead.

git-svn-id: http://svn.osgeo.org/postgis/trunk@8778 b70326c6-7e19-0410-871a-916f4a2858ee

postgis/gserialized_gist_2d.c
regress/empty.sql
regress/empty_expected
regress/tickets.sql
regress/tickets_expected

index 84efa9e9ec3d1c51cc9f0aac45ed35b42153d5b4..ff85b2ab05a80fefe1cb5e6ff817093fcef6cd6e 100644 (file)
@@ -238,6 +238,8 @@ static inline void box2df_validate(BOX2DF *b)
 
 static bool box2df_overlaps(const BOX2DF *a, const BOX2DF *b)
 {
+       if ( ! a || ! b ) return FALSE; /* TODO: might be smarter for EMPTY */
+
        if ( (a->xmin > b->xmax) || (b->xmin > a->xmax) ||
             (a->ymin > b->ymax) || (b->ymin > a->ymax) )
        {
@@ -249,6 +251,8 @@ static bool box2df_overlaps(const BOX2DF *a, const BOX2DF *b)
 
 static bool box2df_contains(const BOX2DF *a, const BOX2DF *b)
 {
+       if ( ! a || ! b ) return FALSE; /* TODO: might be smarter for EMPTY */
+
        if ( (a->xmin > b->xmin) || (a->xmax < b->xmax) ||
             (a->ymin > b->ymin) || (a->ymax < b->ymax) )
        {
@@ -260,65 +264,90 @@ static bool box2df_contains(const BOX2DF *a, const BOX2DF *b)
 
 static bool box2df_within(const BOX2DF *a, const BOX2DF *b)
 {
+       if ( ! a || ! b ) return FALSE; /* TODO: might be smarter for EMPTY */
+
        POSTGIS_DEBUG(5, "entered function");
        return box2df_contains(b,a);
 }
 
 static bool box2df_equals(const BOX2DF *a, const BOX2DF *b)
 {
-       if ( (a->xmin != b->xmin) || (a->xmax != b->xmax) ||
-            (a->ymin != b->ymin) || (a->ymax != b->ymax) )
-       {
+       if ( a &&  b ) {
+               if ( (a->xmin != b->xmin) || (a->xmax != b->xmax) ||
+                    (a->ymin != b->ymin) || (a->ymax != b->ymax) )
+               {
+                       return FALSE;
+               }
+               return TRUE;
+       } else if ( a || b ) {
+               /* one empty, one not */
                return FALSE;
+       } else {
+               /* both empty */
+               return TRUE;
        }
-
-       return TRUE;
 }
 
 static bool box2df_overleft(const BOX2DF *a, const BOX2DF *b)
 {
+       if ( ! a || ! b ) return FALSE; /* TODO: might be smarter for EMPTY */
+
        /* a.xmax <= b.xmax */
        return a->xmax <= b->xmax;
 }
 
 static bool box2df_left(const BOX2DF *a, const BOX2DF *b)
 {
+       if ( ! a || ! b ) return FALSE; /* TODO: might be smarter for EMPTY */
+
        /* a.xmax < b.xmin */
        return a->xmax < b->xmin;
 }
 
 static bool box2df_right(const BOX2DF *a, const BOX2DF *b)
 {
+       if ( ! a || ! b ) return FALSE; /* TODO: might be smarter for EMPTY */
+
        /* a.xmin > b.xmax */
        return a->xmin > b->xmax;
 }
 
 static bool box2df_overright(const BOX2DF *a, const BOX2DF *b)
 {
+       if ( ! a || ! b ) return FALSE; /* TODO: might be smarter for EMPTY */
+
        /* a.xmin >= b.xmin */
        return a->xmin >= b->xmin;
 }
 
 static bool box2df_overbelow(const BOX2DF *a, const BOX2DF *b)
 {
+       if ( ! a || ! b ) return FALSE; /* TODO: might be smarter for EMPTY */
+
        /* a.ymax <= b.ymax */
        return a->ymax <= b->ymax;
 }
 
 static bool box2df_below(const BOX2DF *a, const BOX2DF *b)
 {
+       if ( ! a || ! b ) return FALSE; /* TODO: might be smarter for EMPTY */
+
        /* a.ymax < b.ymin */
        return a->ymax < b->ymin;
 }
 
 static bool box2df_above(const BOX2DF *a, const BOX2DF *b)
 {
+       if ( ! a || ! b ) return FALSE; /* TODO: might be smarter for EMPTY */
+
        /* a.ymin > b.ymax */
        return a->ymin > b->ymax;
 }
 
 static bool box2df_overabove(const BOX2DF *a, const BOX2DF *b)
 {
+       if ( ! a || ! b ) return FALSE; /* TODO: might be smarter for EMPTY */
+
        /* a.ymin >= b.ymin */
        return a->ymin >= b->ymin;
 }
@@ -534,16 +563,15 @@ gserialized_datum_get_box2df_p(Datum gsdatum, BOX2DF *box2df)
 static int 
 gserialized_datum_predicate_2d(Datum gs1, Datum gs2, box2df_predicate predicate)
 {
-       BOX2DF b1, b2;
+       BOX2DF b1, b2, *br1=NULL, *br2=NULL;
        POSTGIS_DEBUG(3, "entered function");
 
-       /* Must be able to build box for each argument (ie, not empty geometry)
-          and overlap boxes to return true. */
-       if ( (gserialized_datum_get_box2df_p(gs1, &b1) == LW_SUCCESS) &&
-            (gserialized_datum_get_box2df_p(gs2, &b2) == LW_SUCCESS) &&
-             predicate(&b1, &b2) )
+       if (gserialized_datum_get_box2df_p(gs1, &b1) == LW_SUCCESS) br1 = &b1;
+       if (gserialized_datum_get_box2df_p(gs2, &b2) == LW_SUCCESS) br2 = &b2;
+
+       if ( predicate(br1, br2) )
        {
-               POSTGIS_DEBUGF(3, "got boxes %s and %s", box2df_to_string(&b1), box2df_to_string(&b2));
+               POSTGIS_DEBUGF(3, "got boxes %s and %s", br1 ? box2df_to_string(&b1) : "(null)", br2 ? box2df_to_string(&b2) : "(null)");
                return LW_TRUE;
        }
        return LW_FALSE;
index 784688b5b32fa6f0eb9c23b96b6bf5684773f62a..0e8d6543593937427b31da1b68d9637d4746b7b7 100644 (file)
@@ -133,3 +133,9 @@ WITH inp AS (SELECT
 WITH inp AS (SELECT
  'LINESTRING EMPTY'::geometry as empty
  ) SELECT 'ST_Length(empty) == 0', ST_Length(empty) FROM inp;
+
+
+-- Operators
+
+-- same box, see http://trac.osgeo.org/postgis/ticket/1453
+SELECT '~=', 'POINT EMPTY'::geometry ~= 'POINT EMPTY'::geometry;
index 2c26d135bb92d2f4b963e42b3faee8219e98a170..ad42a04d89e2e0985820a98ff335444e0f16ba2a 100644 (file)
@@ -51,3 +51,4 @@ ST_ExteriorRing(empty) == empty|010200000000000000
 ST_InteriorRingN(empty, n) == NULL|
 ST_Area(empty) == 0|0
 ST_Length(empty) == 0|0
+~=|t
index 38353df571d2a11378356f8c6480f5c6355a54c9..59d3ff057c48e8d3c3453926d6a4030d7262fabb 100644 (file)
@@ -503,6 +503,10 @@ SELECT '010B00004002000000010400004001000000010100004000000000000000000000000000
 SELECT '010C0000400200000001040000400100000001010000400000000000000000000000000000000000000000000000000101000040000000000000F03F000000000000F03F000000000000F03F'::geometry;
 
 
+-- #1453
+SELECT '#1453.1', ST_OrderingEquals('POINT EMPTY', 'POINT EMPTY');
+SELECT '#1453.2', ST_OrderingEquals('POINT EMPTY', 'POINT Z EMPTY');
+
 -- Clean up
 DELETE FROM spatial_ref_sys;
 
index e250707e9498868a46db4cbe82d3dba49594b649..f148a685430ce1d5f40c4059c82b5fee20ae809d 100644 (file)
@@ -167,3 +167,5 @@ ERROR:  MultiPoint cannot contain MultiPoint element
 ERROR:  CompoundCurve cannot contain MultiPoint element
 ERROR:  MultiCurve cannot contain MultiPoint element
 ERROR:  MultiSurface cannot contain MultiPoint element
+#1453.1|t
+#1453.2|f