// Copyright (c) 2018, 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, version 2.0, // as published by the Free Software Foundation. // // This program is also distributed with certain software (including // but not limited to OpenSSL) that is licensed under separate terms, // as designated in a particular file or component or in included license // documentation. The authors of MySQL hereby grant you an additional // permission to link the program and your derivative works with the // separately licensed software that they have included with MySQL. // // 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, version 2.0, 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. /// @file /// /// This file test gis::write_geometry and the gis::Wkb_visitor class. #include "my_config.h" #include #include // unique_ptr #include #include "sql/dd/dd.h" #include "sql/dd/impl/types/spatial_reference_system_impl.h" #include "sql/dd/properties.h" #include "sql/dd/types/spatial_reference_system.h" #include "sql/gis/geometries.h" #include "sql/gis/geometries_cs.h" #include "sql/gis/wkb.h" namespace wkb_writer_unittest { class WkbWriterTest : public ::testing::Test { protected: dd::Spatial_reference_system_impl *m_cartesian_srs; dd::Spatial_reference_system_impl *m_radian_srs; dd::Spatial_reference_system_impl *m_grad_srs; void SetUp() { m_cartesian_srs = dynamic_cast( dd::create_object()); m_cartesian_srs->set_id(3857); m_cartesian_srs->set_name("WGS 84 / Pseudo-Mercator"); m_cartesian_srs->set_created(0UL); m_cartesian_srs->set_last_altered(0UL); m_cartesian_srs->set_organization("EPSG"); m_cartesian_srs->set_organization_coordsys_id(3857); m_cartesian_srs->set_definition( "PROJCS[\"WGS 84 / Pseudo-Mercator\",GEOGCS[\"WGS 84\",DATUM[\"World " "Geodetic System 1984\",SPHEROID[\"WGS " "84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],AUTHORITY[" "\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\"," "\"8901\"]],UNIT[\"degree\",0.017453292519943278,AUTHORITY[\"EPSG\"," "\"9122\"]],AXIS[\"Lat\",NORTH],AXIS[\"Lon\",EAST],AUTHORITY[\"EPSG\"," "\"4326\"]],PROJECTION[\"Popular Visualisation Pseudo " "Mercator\",AUTHORITY[\"EPSG\",\"1024\"]],PARAMETER[\"Latitude of " "natural " "origin\",0,AUTHORITY[\"EPSG\",\"8801\"]],PARAMETER[\"Longitude of " "natural origin\",0,AUTHORITY[\"EPSG\",\"8802\"]],PARAMETER[\"False " "easting\",0,AUTHORITY[\"EPSG\",\"8806\"]],PARAMETER[\"False " "northing\",0,AUTHORITY[\"EPSG\",\"8807\"]],UNIT[\"metre\",1,AUTHORITY[" "\"EPSG\",\"9001\"]],AXIS[\"X\",EAST],AXIS[\"Y\",NORTH],AUTHORITY[" "\"EPSG\",\"3857\"]]"); m_cartesian_srs->set_description(""); m_cartesian_srs->parse_definition(); // EPSG 4326, lat-long (N-E), Greenwich Meridian, but in radians m_radian_srs = dynamic_cast( dd::create_object()); m_radian_srs->set_id(1000000); m_radian_srs->set_name("WGS 84"); m_radian_srs->set_created(0UL); m_radian_srs->set_last_altered(0UL); m_radian_srs->set_organization("EPSG"); m_radian_srs->set_organization_coordsys_id(4326); m_radian_srs->set_definition( "GEOGCS[\"WGS 84\",DATUM[\"World Geodetic System 1984\",SPHEROID[\"WGS " "84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],AUTHORITY[" "\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\"," "\"8901\"]],UNIT[\"radian\",1.0],AXIS[\"Lat\",NORTH],AXIS[\"Lon\",EAST]" ",AUTHORITY[\"EPSG\",\"4326\"]]"); m_radian_srs->set_description(""); m_radian_srs->parse_definition(); // Lat-long (S-W) in grad, Meridian 10 grad East of Greenwich m_grad_srs = dynamic_cast( dd::create_object()); m_grad_srs->set_id(1000001); m_grad_srs->set_name("Tweaked"); m_grad_srs->set_created(0UL); m_grad_srs->set_last_altered(0UL); m_grad_srs->set_organization("EPSG"); m_grad_srs->set_organization_coordsys_id(1000000); m_grad_srs->set_definition( "GEOGCS[\"Tweaked\",DATUM[\"World Geodetic System " "1984\",SPHEROID[\"WGS " "84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],AUTHORITY[" "\"EPSG\",\"6326\"]],PRIMEM[\"10 " "E\",10,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"grad\",0." "01570796326794895,AUTHORITY[\"EPSG\",\"9122\"]],AXIS[\"Lat\",SOUTH]," "AXIS[\"Lon\",WEST],AUTHORITY[\"EPSG\",\"4326\"]]"); m_grad_srs->set_description(""); m_grad_srs->parse_definition(); } void TearDown() { delete m_cartesian_srs; delete m_radian_srs; delete m_grad_srs; } WkbWriterTest() {} private: GTEST_DISALLOW_COPY_AND_ASSIGN_(WkbWriterTest); }; TEST_F(WkbWriterTest, Point) { gis::Cartesian_point cpt(1, 2); gis::Geographic_point gpt(1, 2); // Little-endian POINT(1 2) std::string point( "\x00\x00\x00\x00" // SRID "\x01" // Byte order "\x01\x00\x00\x00" // WKB type "\x00\x00\x00\x00\x00\x00\xf0\x3f" // X "\x00\x00\x00\x00\x00\x00\x00\x40", // Y 25); // Cartesian String srid0_point; gis::write_geometry(nullptr, cpt, &srid0_point); EXPECT_EQ(point.size(), srid0_point.length()); EXPECT_FALSE(memcmp(point.c_str(), srid0_point.c_ptr(), point.size())); String cartesian_point; gis::write_geometry(m_cartesian_srs, cpt, &cartesian_point); EXPECT_EQ(point.size(), cartesian_point.length()); EXPECT_FALSE(memcmp("\x11\x0f\x00\x00", cartesian_point.c_ptr(), 4)); EXPECT_FALSE( memcmp(point.c_str() + 4, cartesian_point.c_ptr() + 4, point.size() - 4)); // Radians String radian_point; gis::write_geometry(m_radian_srs, gpt, &radian_point); EXPECT_EQ(point.size(), radian_point.length()); EXPECT_FALSE(memcmp("\x40\x42\x0f\x00", radian_point.c_ptr(), 4)); EXPECT_FALSE( memcmp(point.c_str() + 4, radian_point.c_ptr() + 4, point.size() - 4)); // Lat-long (S-W), grad, meridian 10 grad East of Greenwich. Point is 1 grad // West (=9 grad East of Greenwich), 2 grad South. gis::Geographic_point grad_pt(0.14137166941154056, -0.031415926535897899); String grad_point; gis::write_geometry(m_grad_srs, grad_pt, &grad_point); EXPECT_EQ(point.size(), grad_point.length()); EXPECT_FALSE(memcmp("\x41\x42\x0f\x00", grad_point.c_ptr(), 4)); EXPECT_FALSE( memcmp(point.c_str() + 4, grad_point.c_ptr() + 4, point.size() - 4)); } TEST_F(WkbWriterTest, Linestring) { gis::Cartesian_linestring cls; cls.push_back(gis::Cartesian_point(0, 0)); cls.push_back(gis::Cartesian_point(0, 0)); gis::Geographic_linestring gls; gls.push_back(gis::Geographic_point(0, 0)); gls.push_back(gis::Geographic_point(0, 0)); // Linestring with two points std::string linestring( "\x00\x00\x00\x00" // SRID "\x01" // Byte order "\x02\x00\x00\x00" // WKB type "\x02\x00\x00\x00" // numPoints "\x00\x00\x00\x00\x00\x00\x00\x00" // X "\x00\x00\x00\x00\x00\x00\x00\x00" // Y "\x00\x00\x00\x00\x00\x00\x00\x00" // X "\x00\x00\x00\x00\x00\x00\x00\x00", // Y 45); // Cartesian String srid0_linestring; gis::write_geometry(nullptr, cls, &srid0_linestring); EXPECT_EQ(linestring.size(), srid0_linestring.length()); EXPECT_FALSE( memcmp(linestring.c_str(), srid0_linestring.c_ptr(), linestring.size())); String cartesian_linestring; gis::write_geometry(m_cartesian_srs, cls, &cartesian_linestring); EXPECT_EQ(linestring.size(), cartesian_linestring.length()); EXPECT_FALSE(memcmp("\x11\x0f\x00\x00", cartesian_linestring.c_ptr(), 4)); EXPECT_FALSE(memcmp(linestring.c_str() + 4, cartesian_linestring.c_ptr() + 4, linestring.size() - 4)); // Radians String radian_linestring; gis::write_geometry(m_radian_srs, gls, &radian_linestring); EXPECT_EQ(linestring.size(), radian_linestring.length()); EXPECT_FALSE(memcmp("\x40\x42\x0f\x00", radian_linestring.c_ptr(), 4)); EXPECT_FALSE(memcmp(linestring.c_str() + 4, radian_linestring.c_ptr() + 4, linestring.size() - 4)); } TEST_F(WkbWriterTest, Polygon) { gis::Cartesian_polygon cpy; gis::Cartesian_linearring cexterior; cexterior.push_back(gis::Cartesian_point(0, 0)); cexterior.push_back(gis::Cartesian_point(0, 0)); cexterior.push_back(gis::Cartesian_point(0, 0)); cexterior.push_back(gis::Cartesian_point(0, 0)); cpy.push_back(cexterior); gis::Cartesian_linearring cinterior; cinterior.push_back(gis::Cartesian_point(0, 0)); cinterior.push_back(gis::Cartesian_point(0, 0)); cinterior.push_back(gis::Cartesian_point(0, 0)); cinterior.push_back(gis::Cartesian_point(0, 0)); cpy.push_back(cinterior); gis::Geographic_polygon gpy; gis::Geographic_linearring gexterior; gexterior.push_back(gis::Geographic_point(0, 0)); gexterior.push_back(gis::Geographic_point(0, 0)); gexterior.push_back(gis::Geographic_point(0, 0)); gexterior.push_back(gis::Geographic_point(0, 0)); gpy.push_back(gexterior); gis::Geographic_linearring ginterior; ginterior.push_back(gis::Geographic_point(0, 0)); ginterior.push_back(gis::Geographic_point(0, 0)); ginterior.push_back(gis::Geographic_point(0, 0)); ginterior.push_back(gis::Geographic_point(0, 0)); gpy.push_back(ginterior); // Polygon with two rings, each with four points std::string polygon( "\x00\x00\x00\x00" // SRID "\x01" // Byte order "\x03\x00\x00\x00" // WKB type "\x02\x00\x00\x00" // numRings "\x04\x00\x00\x00" // numPoints "\x00\x00\x00\x00\x00\x00\x00\x00" // X "\x00\x00\x00\x00\x00\x00\x00\x00" // Y "\x00\x00\x00\x00\x00\x00\x00\x00" // X "\x00\x00\x00\x00\x00\x00\x00\x00" // Y "\x00\x00\x00\x00\x00\x00\x00\x00" // X "\x00\x00\x00\x00\x00\x00\x00\x00" // Y "\x00\x00\x00\x00\x00\x00\x00\x00" // X "\x00\x00\x00\x00\x00\x00\x00\x00" // Y "\x04\x00\x00\x00" // numPoints "\x00\x00\x00\x00\x00\x00\x00\x00" // X "\x00\x00\x00\x00\x00\x00\x00\x00" // Y "\x00\x00\x00\x00\x00\x00\x00\x00" // X "\x00\x00\x00\x00\x00\x00\x00\x00" // Y "\x00\x00\x00\x00\x00\x00\x00\x00" // X "\x00\x00\x00\x00\x00\x00\x00\x00" // Y "\x00\x00\x00\x00\x00\x00\x00\x00" // X "\x00\x00\x00\x00\x00\x00\x00\x00", // Y 149); // Cartesian String srid0_polygon; gis::write_geometry(nullptr, cpy, &srid0_polygon); EXPECT_EQ(polygon.size(), srid0_polygon.length()); EXPECT_FALSE(memcmp(polygon.c_str(), srid0_polygon.c_ptr(), polygon.size())); String cartesian_polygon; gis::write_geometry(m_cartesian_srs, cpy, &cartesian_polygon); EXPECT_EQ(polygon.size(), cartesian_polygon.length()); EXPECT_FALSE(memcmp("\x11\x0f\x00\x00", cartesian_polygon.c_ptr(), 4)); EXPECT_FALSE(memcmp(polygon.c_str() + 4, cartesian_polygon.c_ptr() + 4, polygon.size() - 4)); // Radians String radian_polygon; gis::write_geometry(m_radian_srs, gpy, &radian_polygon); EXPECT_EQ(polygon.size(), radian_polygon.length()); EXPECT_FALSE(memcmp("\x40\x42\x0f\x00", radian_polygon.c_ptr(), 4)); EXPECT_FALSE(memcmp(polygon.c_str() + 4, radian_polygon.c_ptr() + 4, polygon.size() - 4)); } TEST_F(WkbWriterTest, Geometrycollection) { gis::Cartesian_geometrycollection cgc; cgc.push_back(gis::Cartesian_point(1, 2)); gis::Geographic_geometrycollection ggc; ggc.push_back(gis::Geographic_point(1, 2)); // Little-endian GEOMETRYCOLLECTION(POINT(1 2)); std::string geometrycollection( "\x00\x00\x00\x00" // SRID "\x01" // Byte order "\x07\x00\x00\x00" // WKB type "\x01\x00\x00\x00" // numGeometries "\x01" // Byte order "\x01\x00\x00\x00" // WKB type "\x00\x00\x00\x00\x00\x00\xf0\x3f" // X "\x00\x00\x00\x00\x00\x00\x00\x40", // Y 34); // Cartesian String srid0_geometrycollection; gis::write_geometry(nullptr, cgc, &srid0_geometrycollection); EXPECT_EQ(geometrycollection.size(), srid0_geometrycollection.length()); EXPECT_FALSE(memcmp(geometrycollection.c_str(), srid0_geometrycollection.c_ptr(), geometrycollection.size())); String cartesian_geometrycollection; gis::write_geometry(m_cartesian_srs, cgc, &cartesian_geometrycollection); EXPECT_EQ(geometrycollection.size(), cartesian_geometrycollection.length()); EXPECT_FALSE( memcmp("\x11\x0f\x00\x00", cartesian_geometrycollection.c_ptr(), 4)); EXPECT_FALSE(memcmp(geometrycollection.c_str() + 4, cartesian_geometrycollection.c_ptr() + 4, geometrycollection.size() - 4)); // Radians String radian_geometrycollection; gis::write_geometry(m_radian_srs, ggc, &radian_geometrycollection); EXPECT_EQ(geometrycollection.size(), radian_geometrycollection.length()); EXPECT_FALSE( memcmp("\x40\x42\x0f\x00", radian_geometrycollection.c_ptr(), 4)); EXPECT_FALSE(memcmp(geometrycollection.c_str() + 4, radian_geometrycollection.c_ptr() + 4, geometrycollection.size() - 4)); } } // namespace wkb_writer_unittest