// Copyright (c) 2017, 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. #include "sql/gis/geometries.h" #include // std::swap #include "my_dbug.h" #include "sql/gis/geometries_cs.h" #include "sql/gis/geometry_visitor.h" namespace gis { bool Point::accept(Geometry_visitor *v) { return v->visit(this); } template <> double Point::get<0>() const { return m_x; } template <> double Point::get<1>() const { return m_y; } double Point::x() const { return get<0>(); } double Point::y() const { return get<1>(); } template <> void Point::set<0>(double d) { m_x = d; } template <> void Point::set<1>(double d) { m_y = d; } void Point::x(double d) { set<0>(d); } void Point::y(double d) { set<1>(d); } bool Cartesian_linestring::accept(Geometry_visitor *v) { if (!v->visit_enter(this) && m_points.size() > 0) { if (m_points[0].accept(v)) return true; for (decltype(m_points)::size_type i = 1; i < m_points.size(); i++) { if (v->visit(this) || m_points[i].accept(v)) return true; } } return v->visit_leave(this); } void Cartesian_linestring::push_back(const Point &pt) { DBUG_ASSERT(pt.coordinate_system() == Coordinate_system::kCartesian); m_points.push_back(static_cast(pt)); } void Cartesian_linestring::push_back(Point &&pt) { DBUG_ASSERT(pt.coordinate_system() == Coordinate_system::kCartesian); m_points.push_back(static_cast(pt)); } bool Cartesian_linestring::empty() const { return m_points.empty(); } bool Geographic_linestring::accept(Geometry_visitor *v) { if (!v->visit_enter(this) && m_points.size() > 0) { if (m_points[0].accept(v)) return true; for (decltype(m_points)::size_type i = 1; i < m_points.size(); i++) { if (v->visit(this) || m_points[i].accept(v)) return true; } } return v->visit_leave(this); } void Geographic_linestring::push_back(const Point &pt) { DBUG_ASSERT(pt.coordinate_system() == Coordinate_system::kGeographic); m_points.push_back(static_cast(pt)); } void Geographic_linestring::push_back(Point &&pt) { DBUG_ASSERT(pt.coordinate_system() == Coordinate_system::kGeographic); m_points.push_back(static_cast(pt)); } bool Geographic_linestring::empty() const { return m_points.empty(); } bool Cartesian_linearring::accept(Geometry_visitor *v) { if (!v->visit_enter(this) && m_points.size() > 0) { if (m_points[0].accept(v)) return true; for (decltype(m_points)::size_type i = 1; i < m_points.size(); i++) { if (v->visit(this) || m_points[i].accept(v)) return true; } } return v->visit_leave(this); } bool Geographic_linearring::accept(Geometry_visitor *v) { if (!v->visit_enter(this) && m_points.size() > 0) { if (m_points[0].accept(v)) return true; for (decltype(m_points)::size_type i = 1; i < m_points.size(); i++) { if (v->visit(this) || m_points[i].accept(v)) return true; } } return v->visit_leave(this); } bool Cartesian_polygon::accept(Geometry_visitor *v) { if (!v->visit_enter(this)) { if (m_exterior_ring.accept(v)) return true; for (auto &&ring : m_interior_rings) { if (v->visit(this) || ring.accept(v)) return true; } } return v->visit_leave(this); } void Cartesian_polygon::push_back(const Linearring &lr) { DBUG_ASSERT(lr.coordinate_system() == Coordinate_system::kCartesian); if (m_exterior_ring.empty() && m_interior_rings.empty()) m_exterior_ring = static_cast(lr); else m_interior_rings.push_back(static_cast(lr)); } void Cartesian_polygon::push_back(Linearring &&lr) { DBUG_ASSERT(lr.coordinate_system() == Coordinate_system::kCartesian); if (m_exterior_ring.empty() && m_interior_rings.empty()) m_exterior_ring = static_cast(lr); else m_interior_rings.push_back(static_cast(lr)); } bool Cartesian_polygon::empty() const { return m_exterior_ring.empty() && m_interior_rings.empty(); } std::size_t Cartesian_polygon::size() const { std::size_t sz = m_interior_rings.size(); if (!m_exterior_ring.empty()) sz++; return sz; } Linearring &Cartesian_polygon::interior_ring(std::size_t n) { return m_interior_rings[n]; } bool Geographic_polygon::accept(Geometry_visitor *v) { if (!v->visit_enter(this)) { if (m_exterior_ring.accept(v)) return true; for (auto &&ring : m_interior_rings) { if (v->visit(this) || ring.accept(v)) return true; } } return v->visit_leave(this); } Cartesian_linearring &Cartesian_polygon::cartesian_exterior_ring() const { return const_cast(m_exterior_ring); } // Doxygen doesn't understand decltype as it is used here. #ifndef IN_DOXYGEN decltype(Cartesian_polygon::m_interior_rings) & Cartesian_polygon::interior_rings() { return m_interior_rings; } decltype(Cartesian_polygon::m_interior_rings) const & Cartesian_polygon::const_interior_rings() const { return m_interior_rings; } #endif // IN_DOXYGEN void Geographic_polygon::push_back(const Linearring &lr) { DBUG_ASSERT(lr.coordinate_system() == Coordinate_system::kGeographic); if (m_exterior_ring.empty() && m_interior_rings.empty()) m_exterior_ring = static_cast(lr); else m_interior_rings.push_back(static_cast(lr)); } void Geographic_polygon::push_back(Linearring &&lr) { DBUG_ASSERT(lr.coordinate_system() == Coordinate_system::kGeographic); if (m_exterior_ring.empty() && m_interior_rings.empty()) m_exterior_ring = static_cast(lr); else m_interior_rings.push_back(static_cast(lr)); } bool Geographic_polygon::empty() const { return m_exterior_ring.empty() && m_interior_rings.empty(); } std::size_t Geographic_polygon::size() const { std::size_t sz = m_interior_rings.size(); if (!m_exterior_ring.empty()) sz++; return sz; } Geographic_linearring &Geographic_polygon::geographic_exterior_ring() const { return const_cast(m_exterior_ring); } Linearring &Geographic_polygon::interior_ring(std::size_t n) { return m_interior_rings[n]; } // Doxygen doesn't understand decltype as it is used here. #ifndef IN_DOXYGEN decltype(Geographic_polygon::m_interior_rings) & Geographic_polygon::interior_rings() { return m_interior_rings; } decltype(Geographic_polygon::m_interior_rings) const & Geographic_polygon::const_interior_rings() const { return m_interior_rings; } #endif // IN_DOXYGEN Cartesian_geometrycollection::Cartesian_geometrycollection( const Cartesian_geometrycollection &gc) : m_geometries( Malloc_allocator(key_memory_Geometry_objects_data)) { for (Geometry *g : gc.m_geometries) { switch (g->type()) { case Geometry_type::kPoint: m_geometries.push_back( new Cartesian_point(*static_cast(g))); break; case Geometry_type::kLinestring: m_geometries.push_back( new Cartesian_linestring(*static_cast(g))); break; case Geometry_type::kPolygon: m_geometries.push_back( new Cartesian_polygon(*static_cast(g))); break; case Geometry_type::kGeometrycollection: m_geometries.push_back(new Cartesian_geometrycollection( *static_cast(g))); break; case Geometry_type::kMultipoint: m_geometries.push_back( new Cartesian_multipoint(*static_cast(g))); break; case Geometry_type::kMultilinestring: m_geometries.push_back(new Cartesian_multilinestring( *static_cast(g))); break; case Geometry_type::kMultipolygon: m_geometries.push_back(new Cartesian_multipolygon( *static_cast(g))); break; default: DBUG_ASSERT(false); /* purecov: inspected */ } } } bool Cartesian_geometrycollection::accept(Geometry_visitor *v) { if (!v->visit_enter(this) && m_geometries.size() > 0) { if (m_geometries[0]->accept(v)) return true; for (decltype(m_geometries)::size_type i = 1; i < m_geometries.size(); i++) { if (v->visit(this) || m_geometries[i]->accept(v)) return true; } } return v->visit_leave(this); } void Cartesian_geometrycollection::push_back(const Geometry &g) { switch (g.type()) { case Geometry_type::kPoint: m_geometries.push_back( new Cartesian_point(static_cast(g))); break; case Geometry_type::kLinestring: m_geometries.push_back(new Cartesian_linestring( static_cast(g))); break; case Geometry_type::kPolygon: m_geometries.push_back( new Cartesian_polygon(static_cast(g))); break; case Geometry_type::kGeometrycollection: m_geometries.push_back(new Cartesian_geometrycollection( static_cast(g))); break; case Geometry_type::kMultipoint: m_geometries.push_back(new Cartesian_multipoint( static_cast(g))); break; case Geometry_type::kMultilinestring: m_geometries.push_back(new Cartesian_multilinestring( static_cast(g))); break; case Geometry_type::kMultipolygon: m_geometries.push_back(new Cartesian_multipolygon( static_cast(g))); break; default: DBUG_ASSERT(false); /* purecov: inspected */ } } void Cartesian_geometrycollection::push_back(Geometry &&g) { switch (g.type()) { case Geometry_type::kPoint: m_geometries.push_back( new Cartesian_point(static_cast(g))); break; case Geometry_type::kLinestring: m_geometries.push_back( new Cartesian_linestring(static_cast(g))); break; case Geometry_type::kPolygon: m_geometries.push_back( new Cartesian_polygon(static_cast(g))); break; case Geometry_type::kGeometrycollection: m_geometries.push_back(new Cartesian_geometrycollection( static_cast(g))); break; case Geometry_type::kMultipoint: m_geometries.push_back( new Cartesian_multipoint(static_cast(g))); break; case Geometry_type::kMultilinestring: m_geometries.push_back(new Cartesian_multilinestring( static_cast(g))); break; case Geometry_type::kMultipolygon: m_geometries.push_back(new Cartesian_multipolygon( static_cast(g))); break; default: DBUG_ASSERT(false); /* purecov: inspected */ } } bool Cartesian_geometrycollection::empty() const { return m_geometries.empty(); } Geographic_geometrycollection::Geographic_geometrycollection( const Geographic_geometrycollection &gc) : m_geometries( Malloc_allocator(key_memory_Geometry_objects_data)) { for (Geometry *g : gc.m_geometries) { switch (g->type()) { case Geometry_type::kPoint: m_geometries.push_back( new Geographic_point(*static_cast(g))); break; case Geometry_type::kLinestring: m_geometries.push_back(new Geographic_linestring( *static_cast(g))); break; case Geometry_type::kPolygon: m_geometries.push_back( new Geographic_polygon(*static_cast(g))); break; case Geometry_type::kGeometrycollection: m_geometries.push_back(new Geographic_geometrycollection( *static_cast(g))); break; case Geometry_type::kMultipoint: m_geometries.push_back(new Geographic_multipoint( *static_cast(g))); break; case Geometry_type::kMultilinestring: m_geometries.push_back(new Geographic_multilinestring( *static_cast(g))); break; case Geometry_type::kMultipolygon: m_geometries.push_back(new Geographic_multipolygon( *static_cast(g))); break; default: DBUG_ASSERT(false); /* purecov: inspected */ } } } bool Geographic_geometrycollection::accept(Geometry_visitor *v) { if (!v->visit_enter(this) && m_geometries.size() > 0) { if (m_geometries[0]->accept(v)) return true; for (decltype(m_geometries)::size_type i = 1; i < m_geometries.size(); i++) { if (v->visit(this) || m_geometries[i]->accept(v)) return true; } } return v->visit_leave(this); } void Geographic_geometrycollection::push_back(const Geometry &g) { switch (g.type()) { case Geometry_type::kPoint: m_geometries.push_back( new Geographic_point(static_cast(g))); break; case Geometry_type::kLinestring: m_geometries.push_back(new Geographic_linestring( static_cast(g))); break; case Geometry_type::kPolygon: m_geometries.push_back( new Geographic_polygon(static_cast(g))); break; case Geometry_type::kGeometrycollection: m_geometries.push_back(new Geographic_geometrycollection( static_cast(g))); break; case Geometry_type::kMultipoint: m_geometries.push_back(new Geographic_multipoint( static_cast(g))); break; case Geometry_type::kMultilinestring: m_geometries.push_back(new Geographic_multilinestring( static_cast(g))); break; case Geometry_type::kMultipolygon: m_geometries.push_back(new Geographic_multipolygon( static_cast(g))); break; default: DBUG_ASSERT(false); /* purecov: inspected */ } } void Geographic_geometrycollection::push_back(Geometry &&g) { switch (g.type()) { case Geometry_type::kPoint: m_geometries.push_back( new Geographic_point(static_cast(g))); break; case Geometry_type::kLinestring: m_geometries.push_back( new Geographic_linestring(static_cast(g))); break; case Geometry_type::kPolygon: m_geometries.push_back( new Geographic_polygon(static_cast(g))); break; case Geometry_type::kGeometrycollection: m_geometries.push_back(new Geographic_geometrycollection( static_cast(g))); break; case Geometry_type::kMultipoint: m_geometries.push_back( new Geographic_multipoint(static_cast(g))); break; case Geometry_type::kMultilinestring: m_geometries.push_back(new Geographic_multilinestring( static_cast(g))); break; case Geometry_type::kMultipolygon: m_geometries.push_back(new Geographic_multipolygon( static_cast(g))); break; default: DBUG_ASSERT(false); /* purecov: inspected */ } } bool Geographic_geometrycollection::empty() const { return m_geometries.empty(); } bool Cartesian_multipoint::accept(Geometry_visitor *v) { if (!v->visit_enter(this) && m_points.size() > 0) { if (m_points[0].accept(v)) return true; for (decltype(m_points)::size_type i = 1; i < m_points.size(); i++) { if (v->visit(this) || m_points[i].accept(v)) return true; } } return v->visit_leave(this); } void Cartesian_multipoint::push_back(const Geometry &pt) { DBUG_ASSERT(pt.coordinate_system() == Coordinate_system::kCartesian); m_points.push_back(static_cast(pt)); } void Cartesian_multipoint::push_back(Geometry &&pt) { DBUG_ASSERT(pt.coordinate_system() == Coordinate_system::kCartesian); m_points.push_back(static_cast(pt)); } bool Cartesian_multipoint::empty() const { return m_points.empty(); } bool Geographic_multipoint::accept(Geometry_visitor *v) { if (!v->visit_enter(this) && m_points.size() > 0) { if (m_points[0].accept(v)) return true; for (decltype(m_points)::size_type i = 1; i < m_points.size(); i++) { if (v->visit(this) || m_points[i].accept(v)) return true; } } return v->visit_leave(this); } void Geographic_multipoint::push_back(const Geometry &pt) { DBUG_ASSERT(pt.coordinate_system() == Coordinate_system::kGeographic); m_points.push_back(static_cast(pt)); } void Geographic_multipoint::push_back(Geometry &&pt) { DBUG_ASSERT(pt.coordinate_system() == Coordinate_system::kGeographic); m_points.push_back(static_cast(pt)); } bool Geographic_multipoint::empty() const { return m_points.empty(); } bool Cartesian_multilinestring::accept(Geometry_visitor *v) { if (!v->visit_enter(this) && m_linestrings.size() > 0) { if (m_linestrings[0].accept(v)) return true; for (decltype(m_linestrings)::size_type i = 1; i < m_linestrings.size(); i++) { if (v->visit(this) || m_linestrings[i].accept(v)) return true; } } return v->visit_leave(this); } void Cartesian_multilinestring::push_back(const Geometry &ls) { DBUG_ASSERT(ls.coordinate_system() == Coordinate_system::kCartesian); m_linestrings.push_back(static_cast(ls)); } void Cartesian_multilinestring::push_back(Geometry &&ls) { DBUG_ASSERT(ls.coordinate_system() == Coordinate_system::kCartesian); m_linestrings.push_back(static_cast(ls)); } bool Cartesian_multilinestring::empty() const { return m_linestrings.empty(); } bool Geographic_multilinestring::accept(Geometry_visitor *v) { if (!v->visit_enter(this) && m_linestrings.size() > 0) { if (m_linestrings[0].accept(v)) return true; for (decltype(m_linestrings)::size_type i = 1; i < m_linestrings.size(); i++) { if (v->visit(this) || m_linestrings[i].accept(v)) return true; } } return v->visit_leave(this); } void Geographic_multilinestring::push_back(const Geometry &ls) { DBUG_ASSERT(ls.coordinate_system() == Coordinate_system::kGeographic); m_linestrings.push_back(static_cast(ls)); } void Geographic_multilinestring::push_back(Geometry &&ls) { DBUG_ASSERT(ls.coordinate_system() == Coordinate_system::kGeographic); m_linestrings.push_back(static_cast(ls)); } bool Geographic_multilinestring::empty() const { return m_linestrings.empty(); } bool Cartesian_multipolygon::accept(Geometry_visitor *v) { if (!v->visit_enter(this) && m_polygons.size() > 0) { if (m_polygons[0].accept(v)) return true; for (decltype(m_polygons)::size_type i = 1; i < m_polygons.size(); i++) { if (v->visit(this) || m_polygons[i].accept(v)) return true; } } return v->visit_leave(this); } void Cartesian_multipolygon::push_back(const Geometry &py) { DBUG_ASSERT(py.coordinate_system() == Coordinate_system::kCartesian); m_polygons.push_back(static_cast(py)); } void Cartesian_multipolygon::push_back(Geometry &&py) { DBUG_ASSERT(py.coordinate_system() == Coordinate_system::kCartesian); m_polygons.push_back(static_cast(py)); } bool Cartesian_multipolygon::empty() const { return m_polygons.empty(); } bool Geographic_multipolygon::accept(Geometry_visitor *v) { if (!v->visit_enter(this) && m_polygons.size() > 0) { if (m_polygons[0].accept(v)) return true; for (decltype(m_polygons)::size_type i = 1; i < m_polygons.size(); i++) { if (v->visit(this) || m_polygons[i].accept(v)) return true; } } return v->visit_leave(this); } void Geographic_multipolygon::push_back(const Geometry &py) { DBUG_ASSERT(py.coordinate_system() == Coordinate_system::kGeographic); m_polygons.push_back(static_cast(py)); } void Geographic_multipolygon::push_back(Geometry &&py) { DBUG_ASSERT(py.coordinate_system() == Coordinate_system::kGeographic); m_polygons.push_back(static_cast(py)); } bool Geographic_multipolygon::empty() const { return m_polygons.empty(); } const char *type_to_name(Geometry_type type) { switch (type) { case Geometry_type::kPoint: return "POINT"; case Geometry_type::kLinestring: return "LINESTRING"; case Geometry_type::kPolygon: return "POLYGON"; case Geometry_type::kGeometrycollection: return "GEOMCOLLECTION"; case Geometry_type::kMultipoint: return "MULTIPOINT"; case Geometry_type::kMultilinestring: return "MULTILINESTRING"; case Geometry_type::kMultipolygon: return "MULTIPOLYGON"; default: /* purecov: begin inspected */ DBUG_ASSERT(false); return "UNKNOWN"; /* purecov: end */ } } } // namespace gis