From: Sandro Santilli Date: Wed, 11 Jan 2012 17:18:27 +0000 (+0000) Subject: Fix EMPTY ~= EMPTY to return TRUE (#1453) X-Git-Tag: 2.0.0alpha1~102 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=887793cead23a366747c85469ee4a057eb479d06;p=postgis Fix EMPTY ~= EMPTY to return TRUE (#1453) 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 --- diff --git a/postgis/gserialized_gist_2d.c b/postgis/gserialized_gist_2d.c index 84efa9e9e..ff85b2ab0 100644 --- a/postgis/gserialized_gist_2d.c +++ b/postgis/gserialized_gist_2d.c @@ -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; diff --git a/regress/empty.sql b/regress/empty.sql index 784688b5b..0e8d65435 100644 --- a/regress/empty.sql +++ b/regress/empty.sql @@ -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; diff --git a/regress/empty_expected b/regress/empty_expected index 2c26d135b..ad42a04d8 100644 --- a/regress/empty_expected +++ b/regress/empty_expected @@ -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 diff --git a/regress/tickets.sql b/regress/tickets.sql index 38353df57..59d3ff057 100644 --- a/regress/tickets.sql +++ b/regress/tickets.sql @@ -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; diff --git a/regress/tickets_expected b/regress/tickets_expected index e250707e9..f148a6854 100644 --- a/regress/tickets_expected +++ b/regress/tickets_expected @@ -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