/* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "my_config.h" #include #include "my_global.h" #include "gstream.h" #include "spatial.h" namespace gis_algo_unittest { /* Testing Gis_polygon_ring::set_ring_order function. */ class SetRingOrderTest : public ::testing::Test { public: SetRingOrderTest() :my_flags(Geometry::wkb_linestring, 0) { latincc= &my_charset_latin1; } Geometry *geometry_from_text(const String &wkt, String *wkb, Geometry_buffer *geobuf); void set_order_and_compare(const std::string &str, const std::string &str2, bool want_ccw= true); const static uint32 srid= 0; CHARSET_INFO *latincc; String str, str2, wkt, wkt2; Geometry_buffer buffer, buffer2; Geometry::Flags_t my_flags; }; Geometry *SetRingOrderTest::geometry_from_text(const String &wkt, String *wkb, Geometry_buffer *geobuf) { Gis_read_stream trs(wkt.charset(), wkt.ptr(), wkt.length()); wkb->set_charset(&my_charset_bin); wkb->length(0); return Geometry::create_from_wkt(geobuf, &trs, wkb, 1); } void SetRingOrderTest::set_order_and_compare(const std::string &s1, const std::string &s2, bool want_ccw) { wkt.set(s1.c_str(), s1.length(), latincc); wkt2.set(s2.c_str(), s2.length(), latincc); Gis_polygon_ring *ringp= static_cast (geometry_from_text(wkt, &str, &buffer)); DBUG_ASSERT(ringp->get_geotype() == Geometry::wkb_linestring); Gis_polygon_ring ring(ringp->get_ptr(), ringp->get_nbytes(), my_flags, 0U); EXPECT_EQ(ring.set_ring_order(want_ccw), false); ringp= static_cast(geometry_from_text(wkt2, &str2, &buffer2)); DBUG_ASSERT(ringp->get_geotype() == Geometry::wkb_linestring); Gis_polygon_ring ring2(ringp->get_ptr(), ringp->get_nbytes(), my_flags, 0U); EXPECT_EQ(ring2.set_ring_order(want_ccw), false); EXPECT_EQ(str.length(), str2.length()); EXPECT_EQ(memcmp(str.ptr(), str2.ptr(), str.length()), 0); } TEST_F(SetRingOrderTest, SetRingOrderCCW) { SCOPED_TRACE("SetRingOrderCCW"); std::string geom1("linestring(0 0, 0 1, 1 1, 1 0, 0 0)"); std::string geom2("linestring(0 0, 1 0, 1 1, 0 1, 0 0)"); set_order_and_compare(geom1, geom2); } TEST_F(SetRingOrderTest, SetRingOrderCW) { SCOPED_TRACE("SetRingOrderCW"); std::string geom1("linestring(0 0, 0 1, 1 1, 1 0, 0 0)"); std::string geom2("linestring(0 0, 1 0, 1 1, 0 1, 0 0)"); set_order_and_compare(geom1, geom2, false); } TEST_F(SetRingOrderTest, SetRingOrder2CCW) { SCOPED_TRACE("SetRingOrder2CCW"); std::string geom3("linestring(0 0, 0 1, 1 0, 0 0)"); std::string geom4("linestring(0 0, 1 0, 0 1, 0 0)"); set_order_and_compare(geom3, geom4); } TEST_F(SetRingOrderTest, SetRingOrder2CW) { SCOPED_TRACE("SetRingOrder2CW"); std::string geom3("linestring(0 0, 0 1, 1 0, 0 0)"); std::string geom4("linestring(0 0, 1 0, 0 1, 0 0)"); set_order_and_compare(geom3, geom4, false); } TEST_F(SetRingOrderTest, DuplicateMinPointBeforeCCW) { SCOPED_TRACE("DuplicateMinPointBeforeCCW"); std::string geom1("linestring(0 0, 0 1, 1 1, 1 0, 0 0, 0 0, 0 0)"); std::string geom2("linestring(0 0, 0 0, 0 0, 1 0, 1 1, 0 1, 0 0)"); set_order_and_compare(geom1, geom2); } TEST_F(SetRingOrderTest, DuplicateMinPointBeforeCW) { SCOPED_TRACE("DuplicateMinPointBeforeCW"); std::string geom1("linestring(0 0, 0 1, 1 1, 1 0, 0 0, 0 0, 0 0)"); std::string geom2("linestring(0 0, 0 0, 0 0, 1 0, 1 1, 0 1, 0 0)"); set_order_and_compare(geom1, geom2, false); } TEST_F(SetRingOrderTest, DuplicateMinPointAfterCCW) { SCOPED_TRACE("DuplicateMinPointAfterCCW"); std::string geom1("linestring(0 0, 0 0, 0 0, 0 1, 1 1, 1 0, 0 0)"); std::string geom2("linestring(0 0, 1 0, 1 1, 0 1, 0 0, 0 0, 0 0)"); set_order_and_compare(geom1, geom2); } TEST_F(SetRingOrderTest, DuplicateMinPointAfterCW) { SCOPED_TRACE("DuplicateMinPointAfterCW"); std::string geom1("linestring(0 0, 0 0, 0 0, 0 1, 1 1, 1 0, 0 0)"); std::string geom2("linestring(0 0, 1 0, 1 1, 0 1, 0 0, 0 0, 0 0)"); set_order_and_compare(geom1, geom2, false); } TEST_F(SetRingOrderTest, RingDegradedToPointTest) { SCOPED_TRACE("RingDegradedToPointTest"); std::string s1("linestring(0 0, 0 0, 0 0, 0 0, 0 0)"); wkt.set(s1.c_str(), s1.length(), latincc); Gis_polygon_ring *ringp= static_cast (geometry_from_text(wkt, &str, &buffer)); DBUG_ASSERT(ringp->get_geotype() == Geometry::wkb_linestring); Gis_polygon_ring ring(ringp->get_ptr(), ringp->get_nbytes(), my_flags, 0U); EXPECT_EQ(ring.set_ring_order(true/*CCW*/), true); } /* Testing functions in Geometry and its children classes that are not covered by current BG functionalities. */ class GeometryManipulationTest : public SetRingOrderTest { public: void assign_multipolygon_back(Gis_multi_polygon &mpl2, const Gis_polygon &pl) { for (size_t i = 0; i < pl.outer().size(); i++) mpl2.back().outer().push_back(pl.outer()[i]); for (size_t i = 0; i < pl.inners().size(); i+=2) { mpl2.back().inners().push_back(pl.inners()[i]); if (i + 1 < pl.inners().size()) { mpl2.back().inners().resize(mpl2.back().inners().size() + 1); for (size_t j = 0; j < pl.inners()[i+1].size(); j++) mpl2.back().inners().back().push_back(pl.inners()[i+1][j]); } } } }; TEST_F(GeometryManipulationTest, PolygonCopyTest) { SCOPED_TRACE("PolygonCopyTest"); std::string s1("polygon((0 0, 1 0, 1 1, 0 1, 0 0))"); wkt.set(s1.c_str(), s1.length(), latincc); Gis_polygon *plgn= static_cast(geometry_from_text(wkt, &str, &buffer)); Gis_polygon plgn1(plgn->get_data_ptr(), plgn->get_data_size(), plgn->get_flags(), plgn->get_srid()); Gis_polygon plgn2(plgn1); Gis_polygon plgn3; plgn3= plgn2; String wkb3, wkb4, wkb5; plgn3.as_wkb(&wkb3, false); plgn3.to_wkb_unparsed(); plgn3.as_wkb(&wkb5, true); EXPECT_EQ(wkb3.length(), wkb5.length()); EXPECT_EQ(memcmp(((char *)wkb3.ptr()) + WKB_HEADER_SIZE, ((char *)wkb5.ptr()) + WKB_HEADER_SIZE, wkb5.length() - WKB_HEADER_SIZE), 0); plgn2.as_geometry(&wkb4, false); EXPECT_EQ(wkb3.length() + 4, wkb4.length()); EXPECT_EQ(memcmp(GEOM_HEADER_SIZE + ((char *)wkb4.ptr()), ((char *)wkb3.ptr()) + WKB_HEADER_SIZE, wkb3.length() - WKB_HEADER_SIZE), 0); // Check they have identical data. Can only do so in wkb form. plgn1.to_wkb_unparsed(); plgn2.to_wkb_unparsed(); EXPECT_EQ(plgn1.get_data_size(), plgn2.get_data_size()); EXPECT_EQ(memcmp(plgn->get_data_ptr(), plgn2.get_data_ptr(), plgn2.get_data_size()), 0); EXPECT_EQ(plgn3.get_data_size(), plgn2.get_data_size()); EXPECT_EQ(memcmp(plgn3.get_data_ptr(), plgn2.get_data_ptr(), plgn2.get_data_size()), 0); } TEST_F(GeometryManipulationTest, PolygonManipulationTest) { SCOPED_TRACE("PolygonManipulationTest"); std::string s1("polygon((0 0, 1 0, 1 1, 0 1, 0 0))"); std::string s2("multipolygon(((0 0, 1 0, 1 1, 0 1, 0 0)))"); std::string s3("linestring(0.5 0.25, 0.5 0.75, 0.75 0.75, 0.5 0.25)"); std::string s4("multipolygon(((0 0, 1 0, 1 1, 0 1, 0 0)), \ ((0 0, 1 0, 1 1, 0 1, 0 0), (0.5 0.25, 0.5 0.75, 0.75 0.75, 0.5 0.25)),\ ((0 0, 1 0, 1 1, 0 1, 0 0), (0.5 0.25, 0.5 0.75, 0.75 0.75, 0.5 0.25)))"); std::string s5("polygon((0 0, 1 0, 1 1, 0 1, 0 0),\ (0.5 0.25, 0.5 0.75, 0.75 0.75, 0.5 0.25))"); wkt.set(s1.c_str(), s1.length(), latincc); wkt2.set(s3.c_str(), s3.length(), latincc); Gis_polygon *plgn0= static_cast(geometry_from_text(wkt, &str, &buffer)); Gis_line_string *ls0= static_cast(geometry_from_text(wkt2, &str2, &buffer2)); Gis_polygon plgn(plgn0->get_data_ptr(), plgn0->get_data_size(), plgn0->get_flags(), plgn0->get_srid()); Gis_line_string ls(ls0->get_data_ptr(), ls0->get_data_size(), ls0->get_flags(), ls0->get_srid()); Gis_line_string ls00(*ls0); ls= ls; ls00= ls00; plgn= plgn; Geometry_buffer buffer3; String wkt3, str3; wkt3.set(s2.c_str(), s2.length(), latincc); Gis_multi_polygon *pmplgn= (static_cast (geometry_from_text(wkt3, &str3, &buffer3))); Gis_multi_polygon mplgn0(pmplgn->get_data_ptr(), pmplgn->get_data_size(), pmplgn->get_flags(), pmplgn->get_srid()); EXPECT_EQ(mplgn0.size(), 1U); Gis_multi_polygon mplgn= mplgn0; plgn.inners().resize(1); for (int i= 0; i < 4; i++) (plgn.inners())[0].push_back(ls[i]); mplgn.push_back(plgn); plgn.to_wkb_unparsed(); Geometry_buffer buffer5; String wkt5, str5; wkt5.set(s5.c_str(), s5.length(), latincc); Gis_polygon *plgn20= static_cast(geometry_from_text(wkt5, &str5, &buffer5)); Gis_polygon plgn2(plgn20->get_data_ptr(), plgn20->get_data_size(), plgn20->get_flags(), plgn20->get_srid()); EXPECT_EQ(plgn.get_data_size(), plgn2.get_nbytes()); mplgn.push_back(plgn2); plgn2.to_wkb_unparsed(); EXPECT_EQ(memcmp(plgn.get_data_ptr(), plgn2.get_data_ptr(), plgn2.get_data_size()), 0); Geometry_buffer buffer4; String wkt4, str4; wkt4.set(s4.c_str(), s4.length(), latincc); Gis_multi_polygon *mplgn2= static_cast(geometry_from_text(wkt4, &str4, &buffer4)); EXPECT_EQ(mplgn.get_data_size(), mplgn2->get_data_size()); EXPECT_EQ(memcmp(mplgn.get_data_ptr(), mplgn2->get_data_ptr(), mplgn2->get_data_size()), 0); } TEST_F(GeometryManipulationTest, ResizeAssignmentTest) { Gis_polygon_ring ring1; Gis_line_string ls4, ls5, ls6, ls7, ls8; for (int i = 0; i < 5; i++) { Gis_point pt; pt.set<0>(i); pt.set<1>(i); ring1.push_back(pt); ls4.push_back(pt); ls6.push_back(pt); ls7.push_back(pt); if (i != 4) ls8.push_back(pt); } Gis_point pt; pt.set<0>(0); pt.set<1>(0); ls7.push_back(pt); Gis_polygon plgn3, plgn4, plgn5; plgn3.outer() = ring1; plgn3.inners().push_back(ring1); plgn3.inners().resize(plgn3.inners().size()); plgn5.outer() = *((Gis_polygon_ring *)(&ls8)); plgn5.inners().push_back(*((Gis_polygon_ring *)(&ls7))); plgn5.inners().push_back(*((Gis_polygon_ring *)(&ls6))); Gis_multi_polygon mplgn3, mplgn4; mplgn3.push_back(plgn3); mplgn3.resize(2); assign_multipolygon_back(mplgn3, plgn5); mplgn3.push_back(plgn3); mplgn3.resize(4); assign_multipolygon_back(mplgn3, plgn5); mplgn4.resize(1); assign_multipolygon_back(mplgn4, plgn3); mplgn4.push_back(plgn5); mplgn4.resize(3); assign_multipolygon_back(mplgn4, plgn3); mplgn4.push_back(plgn5); mplgn3.reassemble(); mplgn4.reassemble(); EXPECT_EQ(mplgn3.get_ptr() != mplgn4.get_ptr() && mplgn3.get_nbytes() == mplgn4.get_nbytes() && memcmp(mplgn3.get_ptr(), mplgn4.get_ptr(), mplgn3.get_nbytes()) == 0, true); Gis_multi_line_string mls1, mls2; mls1.resize(1); for (size_t i= 0; i < ls4.size(); i++) mls1.back().push_back(ls4[i]); mls1.push_back(ls6); mls1.resize(3); for (size_t i= 0; i < ls7.size(); i++) mls1.back().push_back(ls7[i]); mls1.push_back(ls8); mls2.push_back(ls4); mls2.resize(2); for (size_t i= 0; i < ls6.size(); i++) mls2.back().push_back(ls6[i]); mls2.push_back(ls7); mls2.resize(4); for (size_t i= 0; i < ls8.size(); i++) mls2.back().push_back(ls8[i]); mls1.reassemble(); mls2.reassemble(); EXPECT_EQ(mls1.get_ptr() != mls2.get_ptr() && mls1.get_nbytes() == mls2.get_nbytes() && memcmp(mls1.get_ptr(), mls2.get_ptr(), mls1.get_nbytes()) == 0, true); String str1, str2; str1.append(mls1.get_cptr(), mls1.get_nbytes(), &my_charset_bin); Gis_geometry_collection geocol(0, Geometry::wkb_multipolygon, &str1, &str2); ls4= ls5; EXPECT_EQ(ls4.get_ptr() == NULL && ls4.get_nbytes() == 0, true); EXPECT_EQ(ls5.get_ptr() == NULL && ls5.get_nbytes() == 0, true); plgn3= plgn4; plgn3.to_wkb_unparsed(); EXPECT_EQ(plgn3.get_ptr() == NULL && plgn3.get_nbytes() == 0, true); ls4= ls6; EXPECT_EQ(ls4.get_ptr() != ls6.get_ptr() && ls4.get_nbytes() == ls6.get_nbytes() && memcmp(ls4.get_ptr(), ls6.get_ptr(), ls6.get_nbytes()) == 0, true); ls4= ls7; EXPECT_EQ(ls4.get_ptr() != ls7.get_ptr() && ls4.get_nbytes() == ls7.get_nbytes() && memcmp(ls4.get_ptr(), ls7.get_ptr(), ls7.get_nbytes()) == 0, true); ls4= ls6; EXPECT_EQ(ls4.get_ptr() != ls6.get_ptr() && ls4.get_nbytes() == ls6.get_nbytes() && memcmp(ls4.get_ptr(), ls6.get_ptr(), ls6.get_nbytes()) == 0, true); void *buf= gis_wkb_alloc(ls8.get_nbytes() + 32); memcpy(buf, ls8.get_ptr(), ls8.get_nbytes()); char *cbuf= static_cast(buf); memset(cbuf + ls8.get_nbytes(), 0xff, 32); cbuf[ls8.get_nbytes() + 31] = '\0'; ls4.set_ptr(buf, ls8.get_nbytes()); EXPECT_EQ(ls4.get_ptr() != ls8.get_ptr() && ls4.get_nbytes() == ls8.get_nbytes() && memcmp(ls4.get_ptr(), ls8.get_ptr(), ls8.get_nbytes()) == 0, true); for (size_t i= ls4.size() + 1; i < 64; i++) { ls4.resize(i); ls4.back().set<0>(i); ls4.back().set<1>(i); } } /* Tests of miscellineous GIS functionalities. */ class GisMiscTests : public ::testing::Test { public: }; TEST_F(GisMiscTests, PointxyDistanceTest) { const point_xy pt1(1.0, 1.0); const point_xy pt2(1e300, -1e300); const point_xy pt3(1e300, 1); const point_xy pt4(1, 1e300); const point_xy pt5(pt2); EXPECT_FALSE(my_isfinite(pt1.distance(pt2))); EXPECT_FALSE(my_isfinite(pt1.distance(pt3))); EXPECT_FALSE(my_isfinite(pt1.distance(pt4))); EXPECT_FALSE(my_isfinite(pt2.distance(pt3))); EXPECT_FALSE(my_isfinite(pt2.distance(pt4))); EXPECT_FALSE(my_isfinite(pt3.distance(pt4))); EXPECT_FLOAT_EQ(0.0, pt2.distance(pt5)); } }