sql/gis/functor.h (507 lines of code) (raw):
#ifndef GIS__FUNCTOR_H_INCLUDED
#define GIS__FUNCTOR_H_INCLUDED
// Copyright (c) 2017, 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, 51 Franklin
// Street, Suite 500, Boston, MA 02110-1335 USA.
/// @file
///
/// This file contains the superclass for GIS functors.
///
/// Each GIS function is split in two: a functor class (for internal use) and a
/// function (for external use) that uses the functor. The functor provides the
/// internal interface to GIS functions, and it may throw exceptions. Some
/// functions may need a combination of different functors to implement the
/// desired functionality.
///
/// The function, not the functor, is the interface to the rest of MySQL.
///
/// @see distance_functor.h
#include <exception>
#include "geometries.h"
#include "geometries_cs.h"
#include "my_dbug.h" // DBUG_ASSERT
#include "template_utils.h" // down_cast
namespace gis {
/// Function/parameter combination not implemented exception.
///
/// Thrown by GIS functors for parameter combinations that have not been
/// implemented.
class not_implemented_exception : public std::exception {
private:
/// Type of coordinate system.
Coordinate_system m_coordinate_system;
/// Type of first geometry.
Geometry_type m_type1;
/// Type for second geometry.
Geometry_type m_type2;
const char *type_to_name(Geometry_type type) const {
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 "GEOMETRYCOLLECTION";
case Geometry_type::kMultipoint:
return "MULTIPOINT";
case Geometry_type::kMultilinestring:
return "MULTILINESTRING";
case Geometry_type::kMultipolygon:
return "MULTIPOLYGON";
default:
DBUG_ASSERT(false); /* purecov: inspected */
return "UNKNOWN";
}
}
public:
not_implemented_exception(Coordinate_system cs, Geometry_type t1,
Geometry_type t2)
: m_coordinate_system(cs), m_type1(t1), m_type2(t2) {}
Coordinate_system coordinate_system() const { return m_coordinate_system; }
const char *type_name(int geometry_number) const {
if (geometry_number == 1)
return type_to_name(m_type1);
else if (geometry_number == 2)
return type_to_name(m_type2);
else {
DBUG_ASSERT(false); /* purecov: inspected */
return "UNKNOWN";
}
}
};
/// NULL value exception.
///
/// Thrown when the functor discovers that the result is NULL. Normally, NULL
/// returns can be detected before calling the functor, but not always.
class null_value_exception : public std::exception {};
/// The base class of all functors that takes two geometry arguments.
///
/// Subclasses of this functor base class will implement operator() and call
/// apply() to do type combination dispatching. The actual body of the functor
/// is in the eval() member function, which must be implemented for each
/// different parameter type combination.
///
/// The functor may throw exceptions.
///
/// @tparam T The return type of the functor.
template <typename T>
class Functor {
public:
virtual T operator()(const Geometry *g1, const Geometry *g2) const = 0;
virtual ~Functor() {}
protected:
template <typename F>
static inline T apply(F &f, const Geometry *g1, const Geometry *g2) {
DBUG_ASSERT(g1->coordinate_system() == g2->coordinate_system());
switch (g1->coordinate_system()) {
case Coordinate_system::kCartesian:
switch (g1->type()) {
case Geometry_type::kPoint:
switch (g2->type()) {
case Geometry_type::kPoint:
return f.eval(down_cast<const Cartesian_point *>(g1),
down_cast<const Cartesian_point *>(g2));
case Geometry_type::kLinestring:
return f.eval(down_cast<const Cartesian_point *>(g1),
down_cast<const Cartesian_linestring *>(g2));
case Geometry_type::kPolygon:
return f.eval(down_cast<const Cartesian_point *>(g1),
down_cast<const Cartesian_polygon *>(g2));
case Geometry_type::kGeometrycollection:
return f.eval(
down_cast<const Cartesian_point *>(g1),
down_cast<const Cartesian_geometrycollection *>(g2));
case Geometry_type::kMultipoint:
return f.eval(down_cast<const Cartesian_point *>(g1),
down_cast<const Cartesian_multipoint *>(g2));
case Geometry_type::kMultilinestring:
return f.eval(down_cast<const Cartesian_point *>(g1),
down_cast<const Cartesian_multilinestring *>(g2));
case Geometry_type::kMultipolygon:
return f.eval(down_cast<const Cartesian_point *>(g1),
down_cast<const Cartesian_multipolygon *>(g2));
case Geometry_type::kGeometry:
DBUG_ASSERT(false); /* purecov: inspected */
throw new not_implemented_exception(g1->coordinate_system(),
g1->type(), g2->type());
}
case Geometry_type::kLinestring:
switch (g2->type()) {
case Geometry_type::kPoint:
return f.eval(down_cast<const Cartesian_linestring *>(g1),
down_cast<const Cartesian_point *>(g2));
case Geometry_type::kLinestring:
return f.eval(down_cast<const Cartesian_linestring *>(g1),
down_cast<const Cartesian_linestring *>(g2));
case Geometry_type::kPolygon:
return f.eval(down_cast<const Cartesian_linestring *>(g1),
down_cast<const Cartesian_polygon *>(g2));
case Geometry_type::kGeometrycollection:
return f.eval(
down_cast<const Cartesian_linestring *>(g1),
down_cast<const Cartesian_geometrycollection *>(g2));
case Geometry_type::kMultipoint:
return f.eval(down_cast<const Cartesian_linestring *>(g1),
down_cast<const Cartesian_multipoint *>(g2));
case Geometry_type::kMultilinestring:
return f.eval(down_cast<const Cartesian_linestring *>(g1),
down_cast<const Cartesian_multilinestring *>(g2));
case Geometry_type::kMultipolygon:
return f.eval(down_cast<const Cartesian_linestring *>(g1),
down_cast<const Cartesian_multipolygon *>(g2));
case Geometry_type::kGeometry:
DBUG_ASSERT(false); /* purecov: inspected */
throw new not_implemented_exception(g1->coordinate_system(),
g1->type(), g2->type());
}
case Geometry_type::kPolygon:
switch (g2->type()) {
case Geometry_type::kPoint:
return f.eval(down_cast<const Cartesian_polygon *>(g1),
down_cast<const Cartesian_point *>(g2));
case Geometry_type::kLinestring:
return f.eval(down_cast<const Cartesian_polygon *>(g1),
down_cast<const Cartesian_linestring *>(g2));
case Geometry_type::kPolygon:
return f.eval(down_cast<const Cartesian_polygon *>(g1),
down_cast<const Cartesian_polygon *>(g2));
case Geometry_type::kGeometrycollection:
return f.eval(
down_cast<const Cartesian_polygon *>(g1),
down_cast<const Cartesian_geometrycollection *>(g2));
case Geometry_type::kMultipoint:
return f.eval(down_cast<const Cartesian_polygon *>(g1),
down_cast<const Cartesian_multipoint *>(g2));
case Geometry_type::kMultilinestring:
return f.eval(down_cast<const Cartesian_polygon *>(g1),
down_cast<const Cartesian_multilinestring *>(g2));
case Geometry_type::kMultipolygon:
return f.eval(down_cast<const Cartesian_polygon *>(g1),
down_cast<const Cartesian_multipolygon *>(g2));
case Geometry_type::kGeometry:
DBUG_ASSERT(false); /* purecov: inspected */
throw new not_implemented_exception(g1->coordinate_system(),
g1->type(), g2->type());
}
case Geometry_type::kGeometrycollection:
switch (g2->type()) {
case Geometry_type::kPoint:
return f.eval(
down_cast<const Cartesian_geometrycollection *>(g1),
down_cast<const Cartesian_point *>(g2));
case Geometry_type::kLinestring:
return f.eval(
down_cast<const Cartesian_geometrycollection *>(g1),
down_cast<const Cartesian_linestring *>(g2));
case Geometry_type::kPolygon:
return f.eval(
down_cast<const Cartesian_geometrycollection *>(g1),
down_cast<const Cartesian_polygon *>(g2));
case Geometry_type::kGeometrycollection:
return f.eval(
down_cast<const Cartesian_geometrycollection *>(g1),
down_cast<const Cartesian_geometrycollection *>(g2));
case Geometry_type::kMultipoint:
return f.eval(
down_cast<const Cartesian_geometrycollection *>(g1),
down_cast<const Cartesian_multipoint *>(g2));
case Geometry_type::kMultilinestring:
return f.eval(
down_cast<const Cartesian_geometrycollection *>(g1),
down_cast<const Cartesian_multilinestring *>(g2));
case Geometry_type::kMultipolygon:
return f.eval(
down_cast<const Cartesian_geometrycollection *>(g1),
down_cast<const Cartesian_multipolygon *>(g2));
case Geometry_type::kGeometry:
DBUG_ASSERT(false); /* purecov: inspected */
throw new not_implemented_exception(g1->coordinate_system(),
g1->type(), g2->type());
}
case Geometry_type::kMultipoint:
switch (g2->type()) {
case Geometry_type::kPoint:
return f.eval(down_cast<const Cartesian_multipoint *>(g1),
down_cast<const Cartesian_point *>(g2));
case Geometry_type::kLinestring:
return f.eval(down_cast<const Cartesian_multipoint *>(g1),
down_cast<const Cartesian_linestring *>(g2));
case Geometry_type::kPolygon:
return f.eval(down_cast<const Cartesian_multipoint *>(g1),
down_cast<const Cartesian_polygon *>(g2));
case Geometry_type::kGeometrycollection:
return f.eval(
down_cast<const Cartesian_multipoint *>(g1),
down_cast<const Cartesian_geometrycollection *>(g2));
case Geometry_type::kMultipoint:
return f.eval(down_cast<const Cartesian_multipoint *>(g1),
down_cast<const Cartesian_multipoint *>(g2));
case Geometry_type::kMultilinestring:
return f.eval(down_cast<const Cartesian_multipoint *>(g1),
down_cast<const Cartesian_multilinestring *>(g2));
case Geometry_type::kMultipolygon:
return f.eval(down_cast<const Cartesian_multipoint *>(g1),
down_cast<const Cartesian_multipolygon *>(g2));
case Geometry_type::kGeometry:
DBUG_ASSERT(false); /* purecov: inspected */
throw new not_implemented_exception(g1->coordinate_system(),
g1->type(), g2->type());
}
case Geometry_type::kMultilinestring:
switch (g2->type()) {
case Geometry_type::kPoint:
return f.eval(down_cast<const Cartesian_multilinestring *>(g1),
down_cast<const Cartesian_point *>(g2));
case Geometry_type::kLinestring:
return f.eval(down_cast<const Cartesian_multilinestring *>(g1),
down_cast<const Cartesian_linestring *>(g2));
case Geometry_type::kPolygon:
return f.eval(down_cast<const Cartesian_multilinestring *>(g1),
down_cast<const Cartesian_polygon *>(g2));
case Geometry_type::kGeometrycollection:
return f.eval(
down_cast<const Cartesian_multilinestring *>(g1),
down_cast<const Cartesian_geometrycollection *>(g2));
case Geometry_type::kMultipoint:
return f.eval(down_cast<const Cartesian_multilinestring *>(g1),
down_cast<const Cartesian_multipoint *>(g2));
case Geometry_type::kMultilinestring:
return f.eval(down_cast<const Cartesian_multilinestring *>(g1),
down_cast<const Cartesian_multilinestring *>(g2));
case Geometry_type::kMultipolygon:
return f.eval(down_cast<const Cartesian_multilinestring *>(g1),
down_cast<const Cartesian_multipolygon *>(g2));
case Geometry_type::kGeometry:
DBUG_ASSERT(false); /* purecov: inspected */
throw new not_implemented_exception(g1->coordinate_system(),
g1->type(), g2->type());
}
case Geometry_type::kMultipolygon:
switch (g2->type()) {
case Geometry_type::kPoint:
return f.eval(down_cast<const Cartesian_multipolygon *>(g1),
down_cast<const Cartesian_point *>(g2));
case Geometry_type::kLinestring:
return f.eval(down_cast<const Cartesian_multipolygon *>(g1),
down_cast<const Cartesian_linestring *>(g2));
case Geometry_type::kPolygon:
return f.eval(down_cast<const Cartesian_multipolygon *>(g1),
down_cast<const Cartesian_polygon *>(g2));
case Geometry_type::kGeometrycollection:
return f.eval(
down_cast<const Cartesian_multipolygon *>(g1),
down_cast<const Cartesian_geometrycollection *>(g2));
case Geometry_type::kMultipoint:
return f.eval(down_cast<const Cartesian_multipolygon *>(g1),
down_cast<const Cartesian_multipoint *>(g2));
case Geometry_type::kMultilinestring:
return f.eval(down_cast<const Cartesian_multipolygon *>(g1),
down_cast<const Cartesian_multilinestring *>(g2));
case Geometry_type::kMultipolygon:
return f.eval(down_cast<const Cartesian_multipolygon *>(g1),
down_cast<const Cartesian_multipolygon *>(g2));
case Geometry_type::kGeometry:
DBUG_ASSERT(false); /* purecov: inspected */
throw new not_implemented_exception(g1->coordinate_system(),
g1->type(), g2->type());
}
case Geometry_type::kGeometry:
DBUG_ASSERT(false); /* purecov: inspected */
throw new not_implemented_exception(g1->coordinate_system(),
g1->type(), g2->type());
} // switch (g1->type())
case Coordinate_system::kGeographic:
switch (g1->type()) {
case Geometry_type::kPoint:
switch (g2->type()) {
case Geometry_type::kPoint:
return f.eval(down_cast<const Geographic_point *>(g1),
down_cast<const Geographic_point *>(g2));
case Geometry_type::kLinestring:
return f.eval(down_cast<const Geographic_point *>(g1),
down_cast<const Geographic_linestring *>(g2));
case Geometry_type::kPolygon:
return f.eval(down_cast<const Geographic_point *>(g1),
down_cast<const Geographic_polygon *>(g2));
case Geometry_type::kGeometrycollection:
return f.eval(
down_cast<const Geographic_point *>(g1),
down_cast<const Geographic_geometrycollection *>(g2));
case Geometry_type::kMultipoint:
return f.eval(down_cast<const Geographic_point *>(g1),
down_cast<const Geographic_multipoint *>(g2));
case Geometry_type::kMultilinestring:
return f.eval(
down_cast<const Geographic_point *>(g1),
down_cast<const Geographic_multilinestring *>(g2));
case Geometry_type::kMultipolygon:
return f.eval(down_cast<const Geographic_point *>(g1),
down_cast<const Geographic_multipolygon *>(g2));
case Geometry_type::kGeometry:
DBUG_ASSERT(false); /* purecov: inspected */
throw new not_implemented_exception(g1->coordinate_system(),
g1->type(), g2->type());
}
case Geometry_type::kLinestring:
switch (g2->type()) {
case Geometry_type::kPoint:
return f.eval(down_cast<const Geographic_linestring *>(g1),
down_cast<const Geographic_point *>(g2));
case Geometry_type::kLinestring:
return f.eval(down_cast<const Geographic_linestring *>(g1),
down_cast<const Geographic_linestring *>(g2));
case Geometry_type::kPolygon:
return f.eval(down_cast<const Geographic_linestring *>(g1),
down_cast<const Geographic_polygon *>(g2));
case Geometry_type::kGeometrycollection:
return f.eval(
down_cast<const Geographic_linestring *>(g1),
down_cast<const Geographic_geometrycollection *>(g2));
case Geometry_type::kMultipoint:
return f.eval(down_cast<const Geographic_linestring *>(g1),
down_cast<const Geographic_multipoint *>(g2));
case Geometry_type::kMultilinestring:
return f.eval(
down_cast<const Geographic_linestring *>(g1),
down_cast<const Geographic_multilinestring *>(g2));
case Geometry_type::kMultipolygon:
return f.eval(down_cast<const Geographic_linestring *>(g1),
down_cast<const Geographic_multipolygon *>(g2));
case Geometry_type::kGeometry:
DBUG_ASSERT(false); /* purecov: inspected */
throw new not_implemented_exception(g1->coordinate_system(),
g1->type(), g2->type());
}
case Geometry_type::kPolygon:
switch (g2->type()) {
case Geometry_type::kPoint:
return f.eval(down_cast<const Geographic_polygon *>(g1),
down_cast<const Geographic_point *>(g2));
case Geometry_type::kLinestring:
return f.eval(down_cast<const Geographic_polygon *>(g1),
down_cast<const Geographic_linestring *>(g2));
case Geometry_type::kPolygon:
return f.eval(down_cast<const Geographic_polygon *>(g1),
down_cast<const Geographic_polygon *>(g2));
case Geometry_type::kGeometrycollection:
return f.eval(
down_cast<const Geographic_polygon *>(g1),
down_cast<const Geographic_geometrycollection *>(g2));
case Geometry_type::kMultipoint:
return f.eval(down_cast<const Geographic_polygon *>(g1),
down_cast<const Geographic_multipoint *>(g2));
case Geometry_type::kMultilinestring:
return f.eval(
down_cast<const Geographic_polygon *>(g1),
down_cast<const Geographic_multilinestring *>(g2));
case Geometry_type::kMultipolygon:
return f.eval(down_cast<const Geographic_polygon *>(g1),
down_cast<const Geographic_multipolygon *>(g2));
case Geometry_type::kGeometry:
DBUG_ASSERT(false); /* purecov: inspected */
throw new not_implemented_exception(g1->coordinate_system(),
g1->type(), g2->type());
}
case Geometry_type::kGeometrycollection:
switch (g2->type()) {
case Geometry_type::kPoint:
return f.eval(
down_cast<const Geographic_geometrycollection *>(g1),
down_cast<const Geographic_point *>(g2));
case Geometry_type::kLinestring:
return f.eval(
down_cast<const Geographic_geometrycollection *>(g1),
down_cast<const Geographic_linestring *>(g2));
case Geometry_type::kPolygon:
return f.eval(
down_cast<const Geographic_geometrycollection *>(g1),
down_cast<const Geographic_polygon *>(g2));
case Geometry_type::kGeometrycollection:
return f.eval(
down_cast<const Geographic_geometrycollection *>(g1),
down_cast<const Geographic_geometrycollection *>(g2));
case Geometry_type::kMultipoint:
return f.eval(
down_cast<const Geographic_geometrycollection *>(g1),
down_cast<const Geographic_multipoint *>(g2));
case Geometry_type::kMultilinestring:
return f.eval(
down_cast<const Geographic_geometrycollection *>(g1),
down_cast<const Geographic_multilinestring *>(g2));
case Geometry_type::kMultipolygon:
return f.eval(
down_cast<const Geographic_geometrycollection *>(g1),
down_cast<const Geographic_multipolygon *>(g2));
case Geometry_type::kGeometry:
DBUG_ASSERT(false); /* purecov: inspected */
throw new not_implemented_exception(g1->coordinate_system(),
g1->type(), g2->type());
}
case Geometry_type::kMultipoint:
switch (g2->type()) {
case Geometry_type::kPoint:
return f.eval(down_cast<const Geographic_multipoint *>(g1),
down_cast<const Geographic_point *>(g2));
case Geometry_type::kLinestring:
return f.eval(down_cast<const Geographic_multipoint *>(g1),
down_cast<const Geographic_linestring *>(g2));
case Geometry_type::kPolygon:
return f.eval(down_cast<const Geographic_multipoint *>(g1),
down_cast<const Geographic_polygon *>(g2));
case Geometry_type::kGeometrycollection:
return f.eval(
down_cast<const Geographic_multipoint *>(g1),
down_cast<const Geographic_geometrycollection *>(g2));
case Geometry_type::kMultipoint:
return f.eval(down_cast<const Geographic_multipoint *>(g1),
down_cast<const Geographic_multipoint *>(g2));
case Geometry_type::kMultilinestring:
return f.eval(
down_cast<const Geographic_multipoint *>(g1),
down_cast<const Geographic_multilinestring *>(g2));
case Geometry_type::kMultipolygon:
return f.eval(down_cast<const Geographic_multipoint *>(g1),
down_cast<const Geographic_multipolygon *>(g2));
case Geometry_type::kGeometry:
DBUG_ASSERT(false); /* purecov: inspected */
throw new not_implemented_exception(g1->coordinate_system(),
g1->type(), g2->type());
}
case Geometry_type::kMultilinestring:
switch (g2->type()) {
case Geometry_type::kPoint:
return f.eval(down_cast<const Geographic_multilinestring *>(g1),
down_cast<const Geographic_point *>(g2));
case Geometry_type::kLinestring:
return f.eval(down_cast<const Geographic_multilinestring *>(g1),
down_cast<const Geographic_linestring *>(g2));
case Geometry_type::kPolygon:
return f.eval(down_cast<const Geographic_multilinestring *>(g1),
down_cast<const Geographic_polygon *>(g2));
case Geometry_type::kGeometrycollection:
return f.eval(
down_cast<const Geographic_multilinestring *>(g1),
down_cast<const Geographic_geometrycollection *>(g2));
case Geometry_type::kMultipoint:
return f.eval(down_cast<const Geographic_multilinestring *>(g1),
down_cast<const Geographic_multipoint *>(g2));
case Geometry_type::kMultilinestring:
return f.eval(
down_cast<const Geographic_multilinestring *>(g1),
down_cast<const Geographic_multilinestring *>(g2));
case Geometry_type::kMultipolygon:
return f.eval(down_cast<const Geographic_multilinestring *>(g1),
down_cast<const Geographic_multipolygon *>(g2));
case Geometry_type::kGeometry:
DBUG_ASSERT(false); /* purecov: inspected */
throw new not_implemented_exception(g1->coordinate_system(),
g1->type(), g2->type());
}
case Geometry_type::kMultipolygon:
switch (g2->type()) {
case Geometry_type::kPoint:
return f.eval(down_cast<const Geographic_multipolygon *>(g1),
down_cast<const Geographic_point *>(g2));
case Geometry_type::kLinestring:
return f.eval(down_cast<const Geographic_multipolygon *>(g1),
down_cast<const Geographic_linestring *>(g2));
case Geometry_type::kPolygon:
return f.eval(down_cast<const Geographic_multipolygon *>(g1),
down_cast<const Geographic_polygon *>(g2));
case Geometry_type::kGeometrycollection:
return f.eval(
down_cast<const Geographic_multipolygon *>(g1),
down_cast<const Geographic_geometrycollection *>(g2));
case Geometry_type::kMultipoint:
return f.eval(down_cast<const Geographic_multipolygon *>(g1),
down_cast<const Geographic_multipoint *>(g2));
case Geometry_type::kMultilinestring:
return f.eval(
down_cast<const Geographic_multipolygon *>(g1),
down_cast<const Geographic_multilinestring *>(g2));
case Geometry_type::kMultipolygon:
return f.eval(down_cast<const Geographic_multipolygon *>(g1),
down_cast<const Geographic_multipolygon *>(g2));
case Geometry_type::kGeometry:
DBUG_ASSERT(false); /* purecov: inspected */
throw new not_implemented_exception(g1->coordinate_system(),
g1->type(), g2->type());
}
case Geometry_type::kGeometry:
DBUG_ASSERT(false); /* purecov: inspected */
throw new not_implemented_exception(g1->coordinate_system(),
g1->type(), g2->type());
} // switch (g1->type())
} // switch (g1->coordinate_system())
DBUG_ASSERT(false); /* purecov: inspected */
throw new not_implemented_exception(g1->coordinate_system(), g1->type(),
g2->type());
}
};
} // namespace gis
#endif // GIS__FUNCTOR_H_INCLUDED