用于EagleEye3.0 规则集漏报和误报测试的示例项目,项目收集于github和gitee
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

172 lines
6.0 KiB

5 months ago
// 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.
/// @file
///
/// Implements the is_simple functor and function.
#include "sql/gis/is_simple.h" // gis::is_simple
#include "sql/gis/is_simple_functor.h" // gis::Is_simple
#include <boost/geometry.hpp>
#include "my_dbug.h" // DBUG_ASSERT
#include "sql/dd/types/spatial_reference_system.h" // dd::Spatial_reference_system
#include "sql/gis/functor.h" // gis::null_value_exception
#include "sql/gis/geometries.h" // gis::{Geometry{,_type}, Coordinate_system}
#include "sql/gis/geometries_cs.h" // gis::{Cartesian_*, Geographic_*}
#include "sql/gis/geometries_traits.h" // boost::geometry traits for gis types
#include "sql/gis/intersects_functor.h" // gis::Intersects
#include "sql/gis/touches_functor.h" // gis::Touches
#include "sql/sql_exception_handler.h" // handle_gis_exception
namespace bg = boost::geometry;
namespace gis {
Is_simple::Is_simple(double semi_major, double semi_minor)
: m_geostrat{bg::srs::spheroid<double>(semi_major, semi_minor)},
m_semi_major{semi_major},
m_semi_minor{semi_minor} {}
bool Is_simple::operator()(const Geometry &g) const {
DBUG_ASSERT(!g.is_empty() || g.type() == Geometry_type::kGeometrycollection);
return apply(*this, g);
}
bool Is_simple::eval(const Cartesian_point &g) const {
return bg::is_simple(g);
}
bool Is_simple::eval(const Cartesian_linestring &g) const {
return bg::is_simple(g);
}
bool Is_simple::eval(const Cartesian_polygon &g) const {
return bg::is_simple(g);
}
bool Is_simple::eval(const Cartesian_multipoint &g) const {
return bg::is_simple(g);
}
bool Is_simple::eval(const Cartesian_multipolygon &g) const {
return bg::is_simple(g);
}
bool Is_simple::eval(const Cartesian_multilinestring &g) const {
return bg::is_simple(g);
}
bool Is_simple::eval(const Geographic_point &g) const {
return bg::is_simple(g, m_geostrat);
}
bool Is_simple::eval(const Geographic_linestring &g) const {
return bg::is_simple(g, m_geostrat);
}
bool Is_simple::eval(const Geographic_polygon &g) const {
return bg::is_simple(g, m_geostrat);
}
bool Is_simple::eval(const Geographic_multipoint &g) const {
return bg::is_simple(g, m_geostrat);
}
bool Is_simple::eval(const Geographic_multipolygon &g) const {
return bg::is_simple(g, m_geostrat);
}
bool Is_simple::eval(const Geographic_multilinestring &g) const {
return bg::is_simple(g, m_geostrat);
}
bool Is_simple::eval(const Geometrycollection &g) const {
// Boost does not yet implement operations on geometrycollections. This
// function implements the SQL/MM Spatial specification.
const Is_simple &is_simple = *this;
Intersects intersects{m_semi_major, m_semi_minor};
Touches touches{m_semi_major, m_semi_minor};
auto interiors_intersect = [&](const Geometry &g1, const Geometry &g2) {
// TODO: Express this function in terms of `boost::relate` when that gets a
// functor.
// [intersecting interior] = ([intersecting] and not [touching]).
// Proof by relate mask:
// [T*******] = ([not FF*FF***] and not [FT****** or F**T**** or F***T***])
// However, `touches` throws when applied to two geometries with
// dimentionality zero. Zero-dim geomtries have no boundary, so they cannot
// 'touch'.
// Extend `touches` to give false for zero-dim geometries.
auto extension_of_touches = [&](const Geometry &g1, const Geometry &g2) {
try {
return touches(&g1, &g2);
} catch (const null_value_exception &) {
return false;
}
};
return (intersects(&g1, &g2) && !extension_of_touches(g1, g2));
};
// The two requirements for simplicity of a gemetrycollection as described in
// SQL/MM Part 3 Section 10.1.1 "Description" 9 are..
for (size_t i = 0; i < g.size(); i++) {
// 1) Subgeometries must be simple.
if (!is_simple(g[i])) return false;
// 2) Subgeometries must have mutually non-intersecting interiors.
for (size_t j = 0; j < i; j++)
if (interiors_intersect(g[i], g[j])) return false;
}
return true;
}
bool is_simple(const dd::Spatial_reference_system *srs, const Geometry *g,
const char *func_name, bool *result,
bool *result_null) noexcept {
try {
DBUG_ASSERT(!srs || srs->is_cartesian() || srs->is_geographic());
DBUG_ASSERT(!srs || srs->is_cartesian() == (g->coordinate_system() ==
Coordinate_system::kCartesian));
DBUG_ASSERT(!srs ||
srs->is_geographic() ==
(g->coordinate_system() == Coordinate_system::kGeographic));
*result_null = false;
double semi_major = srs ? srs->semi_major_axis() : 0.0;
double semi_minor = srs ? srs->semi_minor_axis() : 0.0;
*result = Is_simple{semi_major, semi_minor}(*g);
return false;
} catch (...) { /* purecov: inspected */
handle_gis_exception(func_name);
return true;
}
}
} // namespace gis