diff --git a/be/src/geo/geo_types.cpp b/be/src/geo/geo_types.cpp index 19254be105..256f334e64 100644 --- a/be/src/geo/geo_types.cpp +++ b/be/src/geo/geo_types.cpp @@ -1033,10 +1033,45 @@ bool GeoPolygon::contains(const GeoShape* rhs) const { switch (rhs->type()) { case GEO_SHAPE_POINT: { const GeoPoint* point = (const GeoPoint*)rhs; - return _polygon->Contains(*point->point()); + if (!_polygon->Contains(*point->point())) { + return false; + } + + // Point on the edge of polygon doesn't count as "Contians" + for (int i = 0; i < _polygon->num_loops(); ++i) { + const S2Loop* loop = _polygon->loop(i); + for (int j = 0; j < loop->num_vertices(); ++j) { + const S2Point& p1 = loop->vertex(j); + const S2Point& p2 = loop->vertex((j + 1) % loop->num_vertices()); + if (compute_distance_to_line(*point->point(), p1, p2) < TOLERANCE) { + return false; + } + } + } + return true; } case GEO_SHAPE_LINE_STRING: { const GeoLine* line = (const GeoLine*)rhs; + + // solve the problem caused by the `Contains(const S2Polyline)` in the S2 library + // due to the direction of the line segment + for (int i = 0; i < _polygon->num_loops(); ++i) { + const S2Loop* loop = _polygon->loop(i); + for (int j = 0; j < loop->num_vertices(); ++j) { + const S2Point& p1 = loop->vertex(j); + const S2Point& p2 = loop->vertex((j + 1) % loop->num_vertices()); + for (int k = 0; k < line->polyline()->num_vertices() - 1; ++k) { + const S2Point& p3 = line->polyline()->vertex(k); + const S2Point& p4 = line->polyline()->vertex(k + 1); + if ((compute_distance_to_line(p3, p1, p2) < TOLERANCE || + compute_distance_to_line(p4, p1, p2) < TOLERANCE) && + !is_line_touches_line(p1, p2, p3, p4)) { + return false; + } + } + } + } + return _polygon->Contains(*line->polyline()); } case GEO_SHAPE_POLYGON: { @@ -1271,10 +1306,14 @@ bool GeoMultiPolygon::contains(const GeoShape* rhs) const { //All polygons in rhs need to be contained const GeoMultiPolygon* multi_polygon = assert_cast(rhs); for (const auto& other : multi_polygon->polygons()) { + bool is_contains = false; for (const auto& polygon : this->_polygons) { if (polygon->contains(other.get())) { - continue; + is_contains = true; + break; } + } + if (!is_contains) { return false; } } diff --git a/be/test/geo/geo_types_test.cpp b/be/test/geo/geo_types_test.cpp index 55504c5799..5b4310f0ae 100644 --- a/be/test/geo/geo_types_test.cpp +++ b/be/test/geo/geo_types_test.cpp @@ -1482,7 +1482,7 @@ TEST_F(GeoTypesTest, polygon_hole_contains) { GeoPoint point; point.from_coord(20, 20); auto res = polygon->contains(&point); - EXPECT_TRUE(res); + EXPECT_FALSE(res); } } diff --git a/regression-test/data/nereids_p0/sql_functions/spatial_functions/test_gis_function.out b/regression-test/data/nereids_p0/sql_functions/spatial_functions/test_gis_function.out index f6f88cb5fc..2e8abe3638 100644 --- a/regression-test/data/nereids_p0/sql_functions/spatial_functions/test_gis_function.out +++ b/regression-test/data/nereids_p0/sql_functions/spatial_functions/test_gis_function.out @@ -9,6 +9,102 @@ POINT (24.7 56.7) CIRCLE ((111 64), 10000) -- ST_Contains -- +-- POLYGON_Contains_POINT +-- !sql -- +true + +-- !sql -- +false + +-- !sql -- +false + +-- POLYGON_Contains_LINESTRING +-- !sql -- +false + +-- !sql -- +true + +-- !sql -- +false + +-- !sql -- +false + +-- !sql -- +true + +-- !sql -- +true + +-- !sql -- +false + +-- POLYGON_Contains_Polygon +-- !sql -- +true + +-- !sql -- +false + +-- !sql -- +false + +-- !sql -- +true + +-- !sql -- +false + +-- !sql -- +false + +-- !sql -- +true + +-- !sql -- +false + +-- POLYGON_Contains_MULTIPOLYGON +-- !sql -- +true + +-- !sql -- +false + +-- MULTIPOLYGON_Contains_POINT +-- !sql -- +true + +-- !sql -- +true + +-- !sql -- +false + +-- !sql -- +false + +-- !sql -- +false + +-- !sql -- +false + +-- !sql -- +false + +-- !sql -- +true + +-- !sql -- +false + +-- MULTIPOLYGON_Contains_LINESTRING +-- !sql -- +true + -- !sql -- true @@ -24,6 +120,71 @@ true -- !sql -- false +-- !sql -- +false + +-- !sql -- +true + +-- !sql -- +false + +-- MULTIPOLYGON_Contains_POLYGON +-- !sql -- +true + +-- !sql -- +true + +-- !sql -- +false + +-- !sql -- +true + +-- !sql -- +false + +-- !sql -- +false + +-- !sql -- +false + +-- !sql -- +true + +-- !sql -- +false + +-- MULTIPOLYGON_Contains_MULTIPOLYGON +-- !sql -- +true + +-- !sql -- +false + +-- !sql -- +true + +-- !sql -- +false + +-- !sql -- +false + +-- !sql -- +false + +-- !sql -- +true + +-- !sql -- +false + +-- !sql -- +false + -- ST_Intersects -- -- POINT_Intersects -- !sql -- diff --git a/regression-test/suites/nereids_p0/sql_functions/spatial_functions/test_gis_function.groovy b/regression-test/suites/nereids_p0/sql_functions/spatial_functions/test_gis_function.groovy index e8cc4ff96f..f4aa968de7 100644 --- a/regression-test/suites/nereids_p0/sql_functions/spatial_functions/test_gis_function.groovy +++ b/regression-test/suites/nereids_p0/sql_functions/spatial_functions/test_gis_function.groovy @@ -27,9 +27,66 @@ suite("test_gis_function") { qt_sql "SELECT ST_Contains(ST_Polygon(\"POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))\"), ST_Point(5, 5));" qt_sql "SELECT ST_Contains(ST_Polygon(\"POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))\"), ST_Point(50, 50));" qt_sql "SELECT ST_Contains(ST_GeomFromText('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'), ST_GeomFromText('POINT(2 10)'));" - qt_sql "SELECT ST_Contains(ST_GeomFromText(\"POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))\"),ST_GeomFromText(\"MULTIPOLYGON(((2 2, 4 2, 4 4, 2 4, 2 2)), ((6 6, 8 6, 8 8, 6 8, 6 6)))\"));" - qt_sql "SELECT ST_Contains(ST_GeomFromText(\"POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))\"),ST_GeomFromText(\"MULTIPOLYGON(((2 2, 2 8, 8 8, 8 2, 2 2)), ((10 10, 10 15, 15 15, 15 10, 10 10)))\"));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'), ST_GeomFromText('LINESTRING(2 0, 8 0)'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'), ST_GeomFromText('LINESTRING(2 5, 8 5)'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'), ST_GeomFromText('LINESTRING(0 0, 10 0)'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'), ST_GeomFromText('LINESTRING(10 0, 0 0)'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'), ST_GeomFromText('LINESTRING(5 0, 5 5)'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'), ST_GeomFromText('LINESTRING(0 0, 10 10)'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'), ST_GeomFromText('LINESTRING(-0.000001 0, 10 10)'));" + + qt_sql "SELECT ST_Contains(ST_GeomFromText('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'), ST_GeomFromText('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'), ST_GeomFromText('POLYGON((10 10, 20 10, 20 20, 10 20, 10 10))'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'), ST_GeomFromText('POLYGON((0 0, 0 10.000001, 10.000001 10.000001, 10.000001 0, 0 0))'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'), ST_GeomFromText('POLYGON((3 3, 3 7, 7 7, 7 3, 3 3))'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3))'), ST_GeomFromText('POLYGON((4 4, 7 4, 7 7, 4 7, 4 4))'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3))'), ST_GeomFromText('POLYGON((3 3, 8 3, 8 8, 3 8, 3 3))'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3))'), ST_GeomFromText('POLYGON((2.999999 2.999999, 8.000001 2.999999, 8.000001 8.000001, 2.999999 8.000001, 2.999999 2.999999), (3 3, 8 3, 8 8, 3 8, 3 3))'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3))'), ST_GeomFromText('POLYGON((1 1, 9 1, 9 9, 1 9, 1 1), (3.000001 3.000001, 7.999999 3.000001, 7.999999 7.999999, 3.000001 7.999999, 3.000001 3.000001))'));" + + qt_sql "SELECT ST_Contains(ST_GeomFromText('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'),ST_GeomFromText('MULTIPOLYGON(((2 2, 4 2, 4 4, 2 4, 2 2)), ((6 6, 8 6, 8 8, 6 8, 6 6)))'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'),ST_GeomFromText('MULTIPOLYGON(((2 2, 2 8, 8 8, 8 2, 2 2)), ((10 10, 10 15, 15 15, 15 10, 10 10)))'));" + + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0)), ((15 5, 15 10, 20 10, 20 5, 15 5)))'), ST_GeomFromText('POINT(5 5)'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0)), ((15 5, 15 10, 20 10, 20 5, 15 5)))'), ST_GeomFromText('POINT(17 7)'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0)), ((15 5, 15 10, 20 10, 20 5, 15 5)))'), ST_GeomFromText('POINT(12 7)'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0)), ((15 5, 15 10, 20 10, 20 5, 15 5)))'), ST_GeomFromText('POINT(0 5)'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0)), ((15 5, 15 10, 20 10, 20 5, 15 5)))'), ST_GeomFromText('POINT(10 10)'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0), (2 2, 2 8, 8 8, 8 2, 2 2)))'), ST_GeomFromText('POINT(5 5)'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0), (2 2, 2 8, 8 8, 8 2, 2 2)))'), ST_GeomFromText('POINT(2 5)'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0)), ((15 5, 15 10, 20 10, 20 5, 15 5)))'), ST_GeomFromText('POINT(0.000001 0.000001)'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0)), ((15 5, 15 10, 20 10, 20 5, 15 5)))'), ST_GeomFromText('POINT(-0.000001 0)'));" + + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0)), ((15 5, 15 10, 20 10, 20 5, 15 5)))'), ST_GeomFromText('LINESTRING(2 2, 8 8)'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0)), ((15 5, 15 10, 20 10, 20 5, 15 5)))'), ST_GeomFromText('LINESTRING(16 6, 19 9)'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0)), ((15 5, 15 10, 20 10, 20 5, 15 5)))'), ST_GeomFromText('LINESTRING(5 5, 16 6)'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0)), ((15 5, 15 10, 20 10, 20 5, 15 5)))'), ST_GeomFromText('LINESTRING(0 0, 10 10)'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0)), ((15 5, 15 10, 20 10, 20 5, 15 5)))'), ST_GeomFromText('LINESTRING(5 0, 5 10)'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0), (2 2, 2 8, 8 8, 8 2, 2 2)))'), ST_GeomFromText('LINESTRING(3 3, 7 7)'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0), (2 2, 2 8, 8 8, 8 2, 2 2)))'), ST_GeomFromText('LINESTRING(1 1, 9 9)'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0)), ((15 5, 15 10, 20 10, 20 5, 15 5)))'), ST_GeomFromText('LINESTRING(0.000001 0.000001, 9.999999 9.999999)'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0)), ((15 5, 15 10, 20 10, 20 5, 15 5)))'), ST_GeomFromText('LINESTRING(0.000001 0.000001, 10.000001 10.000001)'));" + + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0)), ((15 5, 15 10, 20 10, 20 5, 15 5)))'), ST_GeomFromText('POLYGON((1 1, 1 9, 9 9, 9 1, 1 1))'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0)), ((15 5, 15 10, 20 10, 20 5, 15 5)))'), ST_GeomFromText('POLYGON((16 6, 16 9, 19 9, 19 6, 16 6))'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0)), ((15 5, 15 10, 20 10, 20 5, 15 5)))'), ST_GeomFromText('POLYGON((5 5, 5 15, 15 15, 15 5, 5 5))'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0)), ((15 5, 15 10, 20 10, 20 5, 15 5)))'), ST_GeomFromText('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0)), ((15 5, 15 10, 20 10, 20 5, 15 5)))'), ST_GeomFromText('POLYGON((-5 -5, -5 15, 15 15, 15 -5, -5 -5))'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0), (2 2, 2 8, 8 8, 8 2, 2 2)))'), ST_GeomFromText('POLYGON((3 3, 3 7, 7 7, 7 3, 3 3))'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0), (2 2, 2 8, 8 8, 8 2, 2 2)))'), ST_GeomFromText('POLYGON((1 1, 1 9, 9 9, 9 1, 1 1))'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0)), ((15 5, 15 10, 20 10, 20 5, 15 5)))'), ST_GeomFromText('POLYGON((0.000001 0.000001, 0.000001 9.999999, 9.999999 9.999999, 9.999999 0.000001, 0.000001 0.000001))'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0)), ((15 5, 15 10, 20 10, 20 5, 15 5)))'), ST_GeomFromText('POLYGON((-0.000001 -0.000001, -0.000001 10.000001, 10.000001 10.000001, 10.000001 -0.000001, -0.000001 -0.000001))'));" + + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0)), ((15 5, 15 10, 20 10, 20 5, 15 5)))'), ST_GeomFromText('MULTIPOLYGON(((1 1, 1 5, 5 5, 5 1, 1 1)), ((16 6, 16 9, 19 9, 19 6, 16 6)))'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0)), ((15 5, 15 10, 20 10, 20 5, 15 5)))'), ST_GeomFromText('MULTIPOLYGON(((1 1, 1 5, 5 5, 5 1, 1 1)), ((12 6, 12 9, 14 9, 14 6, 12 6)))'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0)), ((15 5, 15 10, 20 10, 20 5, 15 5)))'), ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0)), ((15 5, 15 10, 20 10, 20 5, 15 5)))'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0), (2 2, 2 8, 8 8, 8 2, 2 2)), ((15 5, 15 10, 20 10, 20 5, 15 5)))'), ST_GeomFromText('MULTIPOLYGON(((1 1, 1 9, 9 9, 9 1, 1 1)), ((16 6, 16 9, 19 9, 19 6, 16 6)))'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0), (2 2, 2 8, 8 8, 8 2, 2 2)), ((15 5, 15 10, 20 10, 20 5, 15 5)))'), ST_GeomFromText('MULTIPOLYGON(((3 3, 3 7, 7 7, 7 3, 3 3)), ((16 6, 16 9, 19 9, 19 6, 16 6)))'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0)), ((15 5, 15 10, 20 10, 20 5, 15 5)))'), ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0)), ((25 5, 25 10, 30 10, 30 5, 25 5)))'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0)), ((15 5, 15 10, 20 10, 20 5, 15 5)))'), ST_GeomFromText('MULTIPOLYGON(((0.000001 0.000001, 0.000001 9.999999, 9.999999 9.999999, 9.999999 0.000001, 0.000001 0.000001)), ((15.000001 5.000001, 15.000001 9.999999, 19.999999 9.999999, 19.999999 5.000001, 15.000001 5.000001)))'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0)), ((15 5, 15 10, 20 10, 20 5, 15 5)))'), ST_GeomFromText('MULTIPOLYGON(((-0.000001 -0.000001, -0.000001 10.000001, 10.000001 10.000001, 10.000001 -0.000001, -0.000001 -0.000001)), ((15 5, 15 10, 20 10, 20 5, 15 5)))'));" + qt_sql "SELECT ST_Contains(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 10 0, 0 0), (3 3, 3 7, 7 7, 7 3, 3 3)), ((15 5, 15 10, 20 10, 20 5, 15 5)))'), ST_GeomFromText('MULTIPOLYGON(((1 1, 1 9, 9 9, 9 1, 1 1), (4 4, 4 6, 6 6, 6 4, 4 4)), ((16 6, 16 9, 19 9, 19 6, 16 6)))'));" qt_sql "SELECT ST_Intersects(ST_Point(0, 0), ST_Point(0, 0));" qt_sql "SELECT ST_Intersects(ST_Point(0, 0), ST_Point(5, 5));"