/** * Copyright (c) 2021 OceanBase * OceanBase CE is licensed under Mulan PubL v2. * You can use this software according to the terms and conditions of the Mulan PubL v2. * You may obtain a copy of Mulan PubL v2 at: * http://license.coscl.org.cn/MulanPubL-2.0 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PubL v2 for more details. */ #include #include #include #include #include #define private public #include "lib/geo/ob_geo_bin.h" #include "lib/geo/ob_geo_tree.h" #include "lib/geo/ob_geo_to_tree_visitor.h" #include "lib/geo/ob_geo_tree_traits.h" #include "lib/geo/ob_geo_bin_traits.h" #include "lib/geo/ob_geo_func_register.h" #include "lib/geo/ob_geo_func_box.h" #include "lib/geo/ob_geo_func_utils.h" #include "lib/json_type/ob_json_common.h" #include "lib/random/ob_random.h" #undef private #include #include #include #include namespace bg = boost::geometry; using namespace oceanbase::common; namespace oceanbase { namespace common { class TestGeoFuncBox : public ::testing::Test { public: TestGeoFuncBox() {} ~TestGeoFuncBox() {} virtual void SetUp() {} virtual void TearDown() {} static void SetUpTestCase() {} static void TearDownTestCase() {} private: // disallow copy DISALLOW_COPY_AND_ASSIGN(TestGeoFuncBox); }; int append_bo(ObJsonBuffer &data, ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) { uint8_t sbo = static_cast(bo); return data.append(reinterpret_cast(&sbo), sizeof(uint8_t)); } int append_type(ObJsonBuffer &data, ObGeoType type, ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) { INIT_SUCC(ret); uint32_t stype = static_cast(type); if (OB_FAIL(data.reserve(sizeof(uint32_t)))) { } else { char *ptr = data.ptr() + data.length(); ObGeoWkbByteOrderUtil::write(ptr, stype, bo); ret = data.set_length(data.length() + sizeof(uint32_t)); } return ret; } int append_uint32(ObJsonBuffer &data, uint32_t val, ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) { INIT_SUCC(ret); if (OB_FAIL(data.reserve(sizeof(uint32_t)))) { } else { char *ptr = data.ptr() + data.length(); ObGeoWkbByteOrderUtil::write(ptr, val, bo); ret = data.set_length(data.length() + sizeof(uint32_t)); } return ret; } int append_double(ObJsonBuffer &data, double val, ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) { INIT_SUCC(ret); if (OB_FAIL(data.reserve(sizeof(double)))) { } else { char *ptr = data.ptr() + data.length(); ObGeoWkbByteOrderUtil::write(ptr, val, bo); ret = data.set_length(data.length() + sizeof(double)); } return ret; } void create_point(ObJsonBuffer &data, double x, double y) { ASSERT_EQ(OB_SUCCESS, append_bo(data)); ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::POINT)); ASSERT_EQ(OB_SUCCESS, append_double(data, x)); ASSERT_EQ(OB_SUCCESS, append_double(data, y)); } void create_line(ObJsonBuffer &data, std::vector > &value) { ASSERT_EQ(OB_SUCCESS, append_bo(data)); ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::LINESTRING)); ASSERT_EQ(OB_SUCCESS, append_uint32(data, value.size())); for (auto &p : value) { ASSERT_EQ(OB_SUCCESS, append_double(data, p.first)); ASSERT_EQ(OB_SUCCESS, append_double(data, p.second)); } } void create_polygon(ObJsonBuffer &data, int lnum, int pnum, std::vector > &value) { ASSERT_EQ(OB_SUCCESS, append_bo(data)); ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::POLYGON)); ASSERT_EQ(OB_SUCCESS, append_uint32(data, lnum)); int i = 0; for (int l = 0; l < lnum; l++) { ASSERT_EQ(OB_SUCCESS, append_uint32(data, pnum)); for (int p = 0; p < pnum; p++) { ASSERT_EQ(OB_SUCCESS, append_double(data, value[i].first)); ASSERT_EQ(OB_SUCCESS, append_double(data, value[i].second)); i++; } } } void create_multipoint(ObJsonBuffer &data, std::vector > &value) { ASSERT_EQ(OB_SUCCESS, append_bo(data)); ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::MULTIPOINT)); ASSERT_EQ(OB_SUCCESS, append_uint32(data, value.size())); for (auto &p : value) { create_point(data, p.first, p.second); } } void create_multiline(ObJsonBuffer &data, int lnum, int pnum, std::vector > &value) { ASSERT_EQ(OB_SUCCESS, append_bo(data)); ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::MULTILINESTRING)); ASSERT_EQ(OB_SUCCESS, append_uint32(data, lnum)); int i = 0; for (int l = 0; l < lnum; l++) { ASSERT_EQ(OB_SUCCESS, append_bo(data)); ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::LINESTRING)); ASSERT_EQ(OB_SUCCESS, append_uint32(data, pnum)); for (int p = 0; p < pnum; p++) { ASSERT_EQ(OB_SUCCESS, append_double(data, value[i].first)); ASSERT_EQ(OB_SUCCESS, append_double(data, value[i].second)); i++; } } } // anum: polygon num; rnum: ring num per polygon; pnum: point num per ring void create_multipolygon( ObJsonBuffer &data, int anum, int rnum, int pnum, std::vector > &value) { ASSERT_EQ(OB_SUCCESS, append_bo(data)); ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::MULTIPOLYGON)); ASSERT_EQ(OB_SUCCESS, append_uint32(data, anum)); int i = 0; for (int a = 0; a < anum; a++) { ASSERT_EQ(OB_SUCCESS, append_bo(data)); ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::POLYGON)); ASSERT_EQ(OB_SUCCESS, append_uint32(data, rnum)); for (int r = 0; r < rnum; r++) { ASSERT_EQ(OB_SUCCESS, append_uint32(data, pnum)); for (int p = 0; p < pnum; p++) { ASSERT_EQ(OB_SUCCESS, append_double(data, value[i].first)); ASSERT_EQ(OB_SUCCESS, append_double(data, value[i].second)); i++; } } } } template bool is_geo_equal(GEO1 &geo1, GEO2 &geo2) { std::stringstream left; std::stringstream right; left << bg::dsv(geo1); right << bg::dsv(geo2); if (left.str() == right.str()) { return true; } std::cout << left.str() << std::endl; std::cout << right.str() << std::endl; return false; } typedef bg::strategy::within::geographic_winding ObPlPaStrategy; typedef bg::strategy::intersection::geographic_segments<> ObLlLaAaStrategy; typedef bg::model::d2::point_xy point_geom_t; typedef bg::model::multi_point mpoint_geom_t; typedef bg::model::linestring line_geom_t; typedef bg::model::multi_linestring mline_geom_t; typedef bg::model::polygon polygon_geom_t; typedef bg::model::multi_polygon mpolygon_geom_t; typedef bg::model::d2::point_xy > point_geog_t; typedef bg::model::multi_point mpoint_geog_t; typedef bg::model::linestring line_geog_t; typedef bg::model::multi_linestring mline_geog_t; typedef bg::model::polygon polygon_geog_t; typedef bg::model::multi_polygon mpolygon_geog_t; TEST_F(TestGeoFuncBox, geom_point) { ObArenaAllocator allocator(ObModIds::TEST); ObJsonBuffer data(&allocator); double x = 1.2; double y = 3.5; create_point(data, x, y); ObIWkbGeomPoint p; p.set_data(data.string()); lib::MemoryContext mem_context; ASSERT_EQ(CURRENT_CONTEXT->CREATE_CONTEXT(mem_context, lib::ContextParam().set_label("GIS_UT")), OB_SUCCESS); ObGeoEvalCtx gis_context(mem_context); gis_context.ut_set_geo_count(1); gis_context.ut_set_geo_arg(0, &p); ObGeogBox *result = NULL; int ret = ObGeoFunc::geo_func::eval(gis_context, result); ASSERT_EQ(OB_SUCCESS, ret); ASSERT_TRUE(result != NULL); ASSERT_EQ(x, result->xmax); ASSERT_EQ(x, result->xmin); ASSERT_EQ(y, result->ymax); ASSERT_EQ(y, result->ymin); } TEST_F(TestGeoFuncBox, geom_linestring) { ObArenaAllocator allocator(ObModIds::TEST); ObJsonBuffer data(&allocator); std::vector > val; val.push_back(std::make_pair(1.5, 1.2)); val.push_back(std::make_pair(2.0, 4.0)); create_line(data, val); ObIWkbGeomLineString line; line.set_data(data.string()); lib::MemoryContext mem_context; ASSERT_EQ(CURRENT_CONTEXT->CREATE_CONTEXT(mem_context, lib::ContextParam().set_label("GIS_UT")), OB_SUCCESS); ObGeoEvalCtx gis_context(mem_context); gis_context.ut_set_geo_count(1); gis_context.ut_set_geo_arg(0, &line); ObGeogBox *result = NULL; int ret = ObGeoFunc::geo_func::eval(gis_context, result); ASSERT_EQ(OB_SUCCESS, ret); ASSERT_TRUE(result != NULL); ASSERT_EQ(2.0, result->xmax); ASSERT_EQ(1.5, result->xmin); ASSERT_EQ(4.0, result->ymax); ASSERT_EQ(1.2, result->ymin); } TEST_F(TestGeoFuncBox, geom_polygon) { ObArenaAllocator allocator(ObModIds::TEST); ObJsonBuffer data(&allocator); std::vector > pol_val; pol_val.push_back(std::make_pair(1, 1)); pol_val.push_back(std::make_pair(1, 3)); pol_val.push_back(std::make_pair(3, 3)); pol_val.push_back(std::make_pair(3, 1)); pol_val.push_back(std::make_pair(1, 1)); create_polygon(data, 1, 5, pol_val); ObIWkbGeomPolygon poly; poly.set_data(data.string()); lib::MemoryContext mem_context; ASSERT_EQ(CURRENT_CONTEXT->CREATE_CONTEXT(mem_context, lib::ContextParam().set_label("GIS_UT")), OB_SUCCESS); ObGeoEvalCtx gis_context(mem_context); gis_context.ut_set_geo_count(1); gis_context.ut_set_geo_arg(0, &poly); ObGeogBox *result = NULL; int ret = ObGeoFunc::geo_func::eval(gis_context, result); ASSERT_EQ(OB_SUCCESS, ret); ASSERT_TRUE(result != NULL); ASSERT_EQ(1.0, result->xmin); ASSERT_EQ(3.0, result->xmax); ASSERT_EQ(1.0, result->ymin); ASSERT_EQ(3.0, result->ymax); } TEST_F(TestGeoFuncBox, geom_multipoint) { ObArenaAllocator allocator(ObModIds::TEST); ObJsonBuffer data1(&allocator); std::vector > val; val.push_back(std::make_pair(1.0, 1.0)); val.push_back(std::make_pair(1.0, 0.0)); val.push_back(std::make_pair(1.0, 2.0)); create_multipoint(data1, val); ObIWkbGeomMultiPoint multi_point; multi_point.set_data(data1.string()); lib::MemoryContext mem_context; ASSERT_EQ(CURRENT_CONTEXT->CREATE_CONTEXT(mem_context, lib::ContextParam().set_label("GIS_UT")), OB_SUCCESS); ObGeoEvalCtx gis_context(mem_context); gis_context.ut_set_geo_count(1); gis_context.ut_set_geo_arg(0, &multi_point); ObGeogBox *result = NULL; int ret = ObGeoFunc::geo_func::eval(gis_context, result); ASSERT_EQ(OB_SUCCESS, ret); ASSERT_TRUE(result != NULL); ASSERT_EQ(1.0, result->xmin); ASSERT_EQ(1.0, result->xmax); ASSERT_EQ(0.0, result->ymin); ASSERT_EQ(2.0, result->ymax); } TEST_F(TestGeoFuncBox, geom_multilinestring) { ObArenaAllocator allocator(ObModIds::TEST); ObJsonBuffer data1(&allocator); std::vector > val; val.push_back(std::make_pair(0.0, 0.0)); val.push_back(std::make_pair(1.0, 1.0)); val.push_back(std::make_pair(1.0, 1.0)); val.push_back(std::make_pair(2.0, 2.0)); val.push_back(std::make_pair(2.0, 2.0)); val.push_back(std::make_pair(3.0, 3.0)); create_multiline(data1, 3, 2, val); ObIWkbGeomMultiLineString multi_line; multi_line.set_data(data1.string()); lib::MemoryContext mem_context; ASSERT_EQ(CURRENT_CONTEXT->CREATE_CONTEXT(mem_context, lib::ContextParam().set_label("GIS_UT")), OB_SUCCESS); ObGeoEvalCtx gis_context(mem_context); gis_context.ut_set_geo_count(1); gis_context.ut_set_geo_arg(0, &multi_line); ObGeogBox *result = NULL; int ret = ObGeoFunc::geo_func::eval(gis_context, result); ASSERT_EQ(OB_SUCCESS, ret); ASSERT_TRUE(result != NULL); ASSERT_EQ(0.0, result->xmin); ASSERT_EQ(3.0, result->xmax); ASSERT_EQ(0.0, result->ymin); ASSERT_EQ(3.0, result->ymax); } TEST_F(TestGeoFuncBox, geom_multipolygon) { ObArenaAllocator allocator(ObModIds::TEST); ObJsonBuffer data1(&allocator); std::vector > val; val.push_back(std::make_pair(1.0, 1.0)); val.push_back(std::make_pair(1.0, 3.0)); val.push_back(std::make_pair(3.0, 3.0)); val.push_back(std::make_pair(3.0, 1.0)); val.push_back(std::make_pair(1.0, 1.0)); val.push_back(std::make_pair(4.0, 4.0)); val.push_back(std::make_pair(4.0, 6.0)); val.push_back(std::make_pair(6.0, 6.0)); val.push_back(std::make_pair(6.0, 4.0)); val.push_back(std::make_pair(4.0, 4.0)); create_multipolygon(data1, 2, 1, 5, val); ObIWkbGeomMultiPolygon multi_poly; multi_poly.set_data(data1.string()); lib::MemoryContext mem_context; ASSERT_EQ(CURRENT_CONTEXT->CREATE_CONTEXT(mem_context, lib::ContextParam().set_label("GIS_UT")), OB_SUCCESS); ObGeoEvalCtx gis_context(mem_context); gis_context.ut_set_geo_count(1); gis_context.ut_set_geo_arg(0, &multi_poly); ObGeogBox *result = NULL; int ret = ObGeoFunc::geo_func::eval(gis_context, result); ASSERT_EQ(OB_SUCCESS, ret); ASSERT_TRUE(result != NULL); ASSERT_EQ(1.0, result->xmin); ASSERT_EQ(6.0, result->xmax); ASSERT_EQ(1.0, result->ymin); ASSERT_EQ(6.0, result->ymax); } TEST_F(TestGeoFuncBox, geom_collection) { ObArenaAllocator allocator(ObModIds::TEST); ObJsonBuffer data(&allocator); ASSERT_EQ(OB_SUCCESS, append_bo(data)); ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::GEOMETRYCOLLECTION)); ASSERT_EQ(OB_SUCCESS, append_uint32(data, 6)); create_point(data, 1.2, 3.5); std::vector > line_val; line_val.push_back(std::make_pair(1.5, 1.2)); line_val.push_back(std::make_pair(2.0, 4.0)); create_line(data, line_val); std::vector > pol_val; pol_val.push_back(std::make_pair(1, 1)); pol_val.push_back(std::make_pair(1, 3)); pol_val.push_back(std::make_pair(3, 3)); pol_val.push_back(std::make_pair(3, 1)); pol_val.push_back(std::make_pair(1, 1)); create_polygon(data, 1, 5, pol_val); std::vector > mpt_val; mpt_val.push_back(std::make_pair(1.0, 1.0)); mpt_val.push_back(std::make_pair(1.0, 0.0)); mpt_val.push_back(std::make_pair(1.0, 2.0)); create_multipoint(data, mpt_val); std::vector > mpl_val; mpl_val.push_back(std::make_pair(0.0, 0.0)); mpl_val.push_back(std::make_pair(1.0, 1.0)); mpl_val.push_back(std::make_pair(1.0, 1.0)); mpl_val.push_back(std::make_pair(2.0, 2.0)); mpl_val.push_back(std::make_pair(2.0, 2.0)); mpl_val.push_back(std::make_pair(3.0, 3.0)); create_multiline(data, 3, 2, mpl_val); std::vector > mpy_val; mpy_val.push_back(std::make_pair(1.0, 1.0)); mpy_val.push_back(std::make_pair(1.0, 3.0)); mpy_val.push_back(std::make_pair(3.0, 3.0)); mpy_val.push_back(std::make_pair(3.0, 1.0)); mpy_val.push_back(std::make_pair(1.0, 1.0)); mpy_val.push_back(std::make_pair(4.0, 4.0)); mpy_val.push_back(std::make_pair(4.0, 6.0)); mpy_val.push_back(std::make_pair(6.0, 6.0)); mpy_val.push_back(std::make_pair(6.0, 4.0)); mpy_val.push_back(std::make_pair(4.0, 4.0)); create_multipolygon(data, 2, 1, 5, mpy_val); ObIWkbGeomCollection collection; collection.set_data(data.string()); lib::MemoryContext mem_context; ASSERT_EQ(CURRENT_CONTEXT->CREATE_CONTEXT(mem_context, lib::ContextParam().set_label("GIS_UT")), OB_SUCCESS); ObGeoEvalCtx gis_context(mem_context); gis_context.ut_set_geo_count(1); gis_context.ut_set_geo_arg(0, &collection); ObGeogBox *result = NULL; int ret = ObGeoFunc::geo_func::eval(gis_context, result); ASSERT_EQ(OB_SUCCESS, ret); ASSERT_TRUE(result != NULL); ASSERT_EQ(0.0, result->xmin); ASSERT_EQ(6.0, result->xmax); ASSERT_EQ(0.0, result->ymin); ASSERT_EQ(6.0, result->ymax); } } // namespace common } // namespace oceanbase int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); // system("rm -f test_geo_func_box.log"); // OB_LOGGER.set_file_name("test_geo_func_box.log"); // OB_LOGGER.set_log_level("INFO"); return RUN_ALL_TESTS(); }