lwgeom_free(geom);
}
+void test_gbox_same_2d(void);
+void test_gbox_same_2d(void)
+{
+ LWGEOM* g1 = lwgeom_from_wkt("LINESTRING(0 0, 1 1)", LW_PARSER_CHECK_NONE);
+ LWGEOM* g2 = lwgeom_from_wkt("LINESTRING(0 0, 0 1, 1 1)", LW_PARSER_CHECK_NONE);
+ LWGEOM* g3 = lwgeom_from_wkt("LINESTRING(0 0, 1 1.000000000001)", LW_PARSER_CHECK_NONE);
+
+ lwgeom_add_bbox(g1);
+ lwgeom_add_bbox(g2);
+ lwgeom_add_bbox(g3);
+
+ CU_ASSERT_TRUE(gbox_same_2d(g1->bbox, g2->bbox));
+ CU_ASSERT_FALSE(gbox_same_2d(g1->bbox, g3->bbox));
+
+ /* Serializing a GBOX with precise coordinates renders the boxes not strictly equal,
+ * but still equal according to gbox_same_2d_float.
+ */
+ GSERIALIZED* s3 = gserialized_from_lwgeom(g3, LW_FALSE, NULL);
+ GBOX s3box;
+ gserialized_read_gbox_p(s3, &s3box);
+
+ CU_ASSERT_FALSE(gbox_same_2d(g3->bbox, &s3box));
+ CU_ASSERT_TRUE(gbox_same_2d_float(g3->bbox, &s3box));
+
+ /* The serialized box equals itself by either the exact or closest-float compares */
+ CU_ASSERT_TRUE(gbox_same_2d(&s3box, &s3box));
+ CU_ASSERT_TRUE(gbox_same_2d_float(&s3box, &s3box));
+
+ lwgeom_free(g1);
+ lwgeom_free(g2);
+ lwgeom_free(g3);
+ lwfree(s3);
+}
+
/*
** Used by test harness to register the tests in this file.
*/
PG_ADD_TEST(suite, test_lwgeom_as_curve);
PG_ADD_TEST(suite, test_lwgeom_scale);
PG_ADD_TEST(suite, test_gserialized_is_empty);
+ PG_ADD_TEST(suite, test_gbox_same_2d);
}
if (FLAGS_GET_ZM(g1->flags) != FLAGS_GET_ZM(g2->flags))
return LW_FALSE;
- if ( g1->xmin != g2->xmin || g1->ymin != g2->ymin ||
- g1->xmax != g2->xmax || g1->ymax != g2->ymax ) return LW_FALSE;
+ if (!gbox_same_2d(g1, g2)) return LW_FALSE;
if (FLAGS_GET_Z(g1->flags) && (g1->zmin != g2->zmin || g1->zmax != g2->zmax))
return LW_FALSE;
return LW_TRUE;
}
+int gbox_same_2d(const GBOX *g1, const GBOX *g2)
+{
+ if (g1->xmin == g2->xmin && g1->ymin == g2->ymin &&
+ g1->xmax == g2->xmax && g1->ymax == g2->ymax)
+ return LW_TRUE;
+ return LW_FALSE;
+}
+
+int gbox_same_2d_float(const GBOX *g1, const GBOX *g2)
+{
+ if ((g1->xmax == g2->xmax || next_float_up(g1->xmax) == next_float_up(g2->xmax)) &&
+ (g1->ymax == g2->ymax || next_float_up(g1->ymax) == next_float_up(g2->ymax)) &&
+ (g1->xmin == g2->xmin || next_float_down(g1->xmin) == next_float_down(g1->xmin)) &&
+ (g1->ymin == g2->ymin || next_float_down(g2->ymin) == next_float_down(g2->ymin)))
+ return LW_TRUE;
+ return LW_FALSE;
+}
+
int gbox_is_valid(const GBOX *gbox)
{
/* X */
*/
extern int gbox_same(const GBOX *g1, const GBOX *g2);
+/**
+* Check if 2 given GBOX are the same in x and y
+*/
+extern int gbox_same_2d(const GBOX *g1, const GBOX *g2);
+
+/**
+* Check if two given GBOX are the same in x and y, or would round to the same
+* GBOX in x and if serialized in GSERIALIZED
+*/
+extern int gbox_same_2d_float(const GBOX *g1, const GBOX *g2);
+
/**
* Round given GBOX to float boundaries
*
PG_RETURN_BOOL(TRUE);
/*
- * short-circuit: Loose test, if geom2 bounding box does not overlap
- * geom1 bounding box we can prematurely return FALSE.
- *
- * TODO: use gbox_same_2d instead (not available at time of writing)
+ * short-circuit: If geom1 and geom2 do not have the same bounding box
+ * we can return FALSE.
*/
- if ( gserialized_get_gbox_p(geom1, &box1) &&
- gserialized_get_gbox_p(geom2, &box2) )
+ if ( gserialized_read_gbox_p(geom1, &box1) &&
+ gserialized_read_gbox_p(geom2, &box2) )
{
- if ( gbox_overlaps_2d(&box1, &box2) == LW_FALSE )
+ if ( gbox_same_2d_float(&box1, &box2) == LW_FALSE )
{
PG_RETURN_BOOL(FALSE);
}