1500 lines
56 KiB
C++
1500 lines
56 KiB
C++
/* Copyright (c) 2015, 2019, 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/item_geofunc_relchecks_bgwrap.h"
|
|
|
|
#include <algorithm>
|
|
#include <boost/concept/usage.hpp>
|
|
#include <boost/geometry/algorithms/equals.hpp>
|
|
#include <boost/geometry/algorithms/intersects.hpp>
|
|
#include <boost/geometry/algorithms/touches.hpp>
|
|
#include <boost/geometry/algorithms/within.hpp>
|
|
#include <boost/geometry/geometries/box.hpp>
|
|
#include <boost/geometry/index/rtree.hpp>
|
|
#include <boost/geometry/strategies/strategies.hpp>
|
|
#include <utility>
|
|
|
|
#include "my_dbug.h"
|
|
#include "sql/item_geofunc_internal.h"
|
|
#include "sql/spatial.h"
|
|
|
|
/**
|
|
Dispatcher for 'point WITHIN xxx'.
|
|
|
|
@tparam Geom_types Geometry types definitions.
|
|
@param g1 First Geometry operand, a point.
|
|
@param g2 Second Geometry operand, not a geometry collection.
|
|
@param[out] pnull_value Returns whether error occurred duirng the computation.
|
|
@return 0 if specified relation doesn't hold for the given operands,
|
|
otherwise returns none 0.
|
|
*/
|
|
template <typename Geom_types>
|
|
int BG_wrap<Geom_types>::point_within_geometry(Geometry *g1, Geometry *g2,
|
|
bool *pnull_value) {
|
|
int result = 0;
|
|
Geometry::wkbType gt2 = g2->get_type();
|
|
|
|
if (gt2 == Geometry::wkb_polygon)
|
|
BGCALL(result, within, Point, g1, Polygon, g2, pnull_value);
|
|
else if (gt2 == Geometry::wkb_multipolygon)
|
|
BGCALL(result, within, Point, g1, Multipolygon, g2, pnull_value);
|
|
else if (gt2 == Geometry::wkb_point)
|
|
BGCALL(result, within, Point, g1, Point, g2, pnull_value);
|
|
else if (gt2 == Geometry::wkb_multipoint)
|
|
BGCALL(result, within, Point, g1, Multipoint, g2, pnull_value);
|
|
else if (gt2 == Geometry::wkb_linestring)
|
|
BGCALL(result, within, Point, g1, Linestring, g2, pnull_value);
|
|
else if (gt2 == Geometry::wkb_multilinestring)
|
|
BGCALL(result, within, Point, g1, Multilinestring, g2, pnull_value);
|
|
else
|
|
DBUG_ASSERT(false);
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
Dispatcher for 'multipoint WITHIN xxx'.
|
|
|
|
@tparam Geom_types Geometry types definitions.
|
|
@param g1 First Geometry operand, a multipoint.
|
|
@param g2 Second Geometry operand, not a geometry collection.
|
|
@param[out] pnull_value Returns whether error occurred duirng the computation.
|
|
@return 0 if specified relation doesn't hold for the given operands,
|
|
otherwise returns none 0.
|
|
*/
|
|
template <typename Geom_types>
|
|
int BG_wrap<Geom_types>::multipoint_within_geometry(Geometry *g1, Geometry *g2,
|
|
bool *pnull_value) {
|
|
int result = 0;
|
|
Geometry::wkbType gt2 = g2->get_type();
|
|
const void *data_ptr = NULL;
|
|
|
|
Multipoint mpts(g1->get_data_ptr(), g1->get_data_size(), g1->get_flags(),
|
|
g1->get_srid());
|
|
if (gt2 == Geometry::wkb_polygon) {
|
|
data_ptr = g2->normalize_ring_order();
|
|
if (data_ptr == NULL) {
|
|
my_error(ER_GIS_INVALID_DATA, MYF(0), "st_within");
|
|
*pnull_value = true;
|
|
return result;
|
|
}
|
|
|
|
Polygon plg(data_ptr, g2->get_data_size(), g2->get_flags(), g2->get_srid());
|
|
|
|
result = multipoint_within_geometry_internal(mpts, plg);
|
|
} else if (gt2 == Geometry::wkb_multipolygon) {
|
|
data_ptr = g2->normalize_ring_order();
|
|
if (data_ptr == NULL) {
|
|
*pnull_value = true;
|
|
my_error(ER_GIS_INVALID_DATA, MYF(0), "st_within");
|
|
return result;
|
|
}
|
|
|
|
Multipolygon mplg(data_ptr, g2->get_data_size(), g2->get_flags(),
|
|
g2->get_srid());
|
|
|
|
/*
|
|
One may want to build the rtree index on mpts when mpts has more
|
|
components than mplg, but then one would have to track the points that
|
|
are already known to be in one of mplg's polygons and avoid checking
|
|
again (which may fail and cause false alarm) for other polygon components.
|
|
Such maintenance brings extra cost and performance test prooves that
|
|
it's not desirable.
|
|
The containers tried for such maintenance including std::vector<bool>,
|
|
std::set<array_index>, mpts[i].set_props().
|
|
|
|
Also, even if the mplg has only one polygon, i.e. the worst case for
|
|
building rtree index on mplg, the performance is still very very close to
|
|
the linear search done in multipoint_within_geometry_internal.
|
|
|
|
So always build index on mplg as below.
|
|
*/
|
|
result = multipoint_within_multipolygon(mpts, mplg);
|
|
} else if (gt2 == Geometry::wkb_point) {
|
|
/* There may be duplicate Points, thus use a set to make them unique*/
|
|
Point_set ptset1(mpts.begin(), mpts.end());
|
|
Point pt(g2->get_data_ptr(), g2->get_data_size(), g2->get_flags(),
|
|
g2->get_srid());
|
|
result =
|
|
((ptset1.size() == 1) && boost::geometry::equals(*ptset1.begin(), pt));
|
|
} else if (gt2 == Geometry::wkb_multipoint) {
|
|
/* There may be duplicate Points, thus use a set to make them unique*/
|
|
Point_set ptset1(mpts.begin(), mpts.end());
|
|
Multipoint mpts2(g2->get_data_ptr(), g2->get_data_size(), g2->get_flags(),
|
|
g2->get_srid());
|
|
Point_set ptset2(mpts2.begin(), mpts2.end());
|
|
Point_vector respts;
|
|
typename Point_vector::iterator endpos;
|
|
respts.resize(std::max(ptset1.size(), ptset2.size()));
|
|
endpos = std::set_intersection(ptset1.begin(), ptset1.end(), ptset2.begin(),
|
|
ptset2.end(), respts.begin(), bgpt_lt());
|
|
result = (ptset1.size() == static_cast<size_t>(endpos - respts.begin()));
|
|
} else if (gt2 == Geometry::wkb_linestring) {
|
|
Linestring ls(g2->get_data_ptr(), g2->get_data_size(), g2->get_flags(),
|
|
g2->get_srid());
|
|
result = multipoint_within_geometry_internal(mpts, ls);
|
|
} else if (gt2 == Geometry::wkb_multilinestring) {
|
|
Multilinestring mls(g2->get_data_ptr(), g2->get_data_size(),
|
|
g2->get_flags(), g2->get_srid());
|
|
/*
|
|
Here we can't separate linestrings of a multilinstring MLS to do within
|
|
check one by one because if N (N > 1) linestrings share the same boundary
|
|
point P, P may or may not be a boundary point of MLS, depending on N%2,
|
|
if N is an even number P is an internal point of MLS, otherwise P is a
|
|
boundary point of MLS.
|
|
*/
|
|
result = multipoint_within_geometry_internal(mpts, mls);
|
|
} else
|
|
DBUG_ASSERT(false);
|
|
|
|
return result;
|
|
}
|
|
|
|
template <typename Geom_types>
|
|
template <typename GeomType>
|
|
int BG_wrap<Geom_types>::multipoint_within_geometry_internal(
|
|
const Multipoint &mpts, const GeomType &geom) {
|
|
bool has_inner = false;
|
|
|
|
for (typename Multipoint::iterator i = mpts.begin(); i != mpts.end(); ++i) {
|
|
/*
|
|
Checking for intersects is faster than within, so if there is at least
|
|
one point within geom, only check that the rest points intersects geom.
|
|
*/
|
|
if (!has_inner && (has_inner = boost::geometry::within(*i, geom))) continue;
|
|
|
|
if (!boost::geometry::intersects(*i, geom)) return 0;
|
|
}
|
|
|
|
return has_inner;
|
|
}
|
|
|
|
template <typename Geom_types>
|
|
int BG_wrap<Geom_types>::multipoint_within_multipolygon(
|
|
const Multipoint &mpts, const Multipolygon &mplgn) {
|
|
bool has_inner = false;
|
|
|
|
Rtree_index rtree;
|
|
make_rtree_bggeom(mplgn, &rtree);
|
|
BG_box box;
|
|
|
|
for (typename Multipoint::iterator i = mpts.begin(); i != mpts.end(); ++i) {
|
|
bool already_in = false;
|
|
// Search for polygons that may intersect *i point using the rtree index.
|
|
boost::geometry::envelope(*i, box);
|
|
Rtree_index::const_query_iterator j = rtree.qbegin(bgi::intersects(box));
|
|
if (j == rtree.qend()) return 0;
|
|
/*
|
|
All polygons that possibly intersect *i point are given by the
|
|
rtree iteration below.
|
|
*/
|
|
for (; j != rtree.qend(); ++j) {
|
|
/*
|
|
Checking for intersects is faster than within, so if there is at least
|
|
one point within geom, only check that the rest points intersects geom.
|
|
*/
|
|
const Polygon &plgn = mplgn[j->second];
|
|
/*
|
|
If we don't have a point in mpts that's within mplgn yet,
|
|
check whether *i is within plgn.
|
|
If *i is within plgn, it's already in the multipolygon, so no need
|
|
for more checks.
|
|
*/
|
|
if (!has_inner && (has_inner = boost::geometry::within(*i, plgn))) {
|
|
already_in = true;
|
|
break;
|
|
}
|
|
|
|
/*
|
|
If we already have a point within mplgn, OR if *i is checked above to
|
|
be not within plgn, check whether *i intersects plgn.
|
|
*i has to intersect one of the components in this loop, otherwise *i
|
|
is out of mplgn.
|
|
*/
|
|
if (boost::geometry::intersects(*i, plgn)) {
|
|
already_in = true;
|
|
/*
|
|
It's likely that *i is within another plgn, so only stop the
|
|
iteration if we already have a point that's within the multipolygon,
|
|
in order not to miss the polygon containing *i.
|
|
*/
|
|
if (has_inner) break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
The *i point isn't within or intersects any polygon of mplgn,
|
|
so mpts isn't within geom.
|
|
*/
|
|
if (!already_in) return 0;
|
|
}
|
|
|
|
/*
|
|
All points in mpts at least intersects geom, so the result is determined
|
|
by whether there is at least one point in mpts that's within geom.
|
|
*/
|
|
return has_inner;
|
|
}
|
|
|
|
template <typename Geom_types>
|
|
int BG_wrap<Geom_types>::linestring_within_geometry(Geometry *g1, Geometry *g2,
|
|
bool *pnull_value) {
|
|
int result = 0;
|
|
Geometry::wkbType gt2 = g2->get_type();
|
|
|
|
if (gt2 == Geometry::wkb_polygon)
|
|
BGCALL(result, within, Linestring, g1, Polygon, g2, pnull_value);
|
|
else if (gt2 == Geometry::wkb_multipolygon)
|
|
BGCALL(result, within, Linestring, g1, Multipolygon, g2, pnull_value);
|
|
else if (gt2 == Geometry::wkb_point || gt2 == Geometry::wkb_multipoint)
|
|
return 0;
|
|
else if (gt2 == Geometry::wkb_linestring)
|
|
BGCALL(result, within, Linestring, g1, Linestring, g2, pnull_value);
|
|
else if (gt2 == Geometry::wkb_multilinestring)
|
|
BGCALL(result, within, Linestring, g1, Multilinestring, g2, pnull_value);
|
|
else
|
|
DBUG_ASSERT(false);
|
|
|
|
return result;
|
|
}
|
|
|
|
template <typename Geom_types>
|
|
int BG_wrap<Geom_types>::multilinestring_within_geometry(Geometry *g1,
|
|
Geometry *g2,
|
|
bool *pnull_value) {
|
|
int result = 0;
|
|
Geometry::wkbType gt2 = g2->get_type();
|
|
|
|
if (gt2 == Geometry::wkb_polygon)
|
|
BGCALL(result, within, Multilinestring, g1, Polygon, g2, pnull_value);
|
|
else if (gt2 == Geometry::wkb_multipolygon)
|
|
BGCALL(result, within, Multilinestring, g1, Multipolygon, g2, pnull_value);
|
|
else if (gt2 == Geometry::wkb_point || gt2 == Geometry::wkb_multipoint)
|
|
return 0;
|
|
else if (gt2 == Geometry::wkb_linestring)
|
|
BGCALL(result, within, Multilinestring, g1, Linestring, g2, pnull_value);
|
|
else if (gt2 == Geometry::wkb_multilinestring)
|
|
BGCALL(result, within, Multilinestring, g1, Multilinestring, g2,
|
|
pnull_value);
|
|
else
|
|
DBUG_ASSERT(false);
|
|
|
|
return result;
|
|
}
|
|
|
|
template <typename Geom_types>
|
|
int BG_wrap<Geom_types>::polygon_within_geometry(Geometry *g1, Geometry *g2,
|
|
bool *pnull_value) {
|
|
int result = 0;
|
|
Geometry::wkbType gt2 = g2->get_type();
|
|
|
|
if (gt2 == Geometry::wkb_polygon)
|
|
BGCALL(result, within, Polygon, g1, Polygon, g2, pnull_value);
|
|
else if (gt2 == Geometry::wkb_multipolygon)
|
|
BGCALL(result, within, Polygon, g1, Multipolygon, g2, pnull_value);
|
|
else if (gt2 == Geometry::wkb_point || gt2 == Geometry::wkb_multipoint ||
|
|
gt2 == Geometry::wkb_linestring ||
|
|
gt2 == Geometry::wkb_multilinestring)
|
|
return 0;
|
|
else
|
|
DBUG_ASSERT(false);
|
|
|
|
return result;
|
|
}
|
|
|
|
template <typename Geom_types>
|
|
int BG_wrap<Geom_types>::multipolygon_within_geometry(Geometry *g1,
|
|
Geometry *g2,
|
|
bool *pnull_value) {
|
|
int result = 0;
|
|
Geometry::wkbType gt2 = g2->get_type();
|
|
|
|
if (gt2 == Geometry::wkb_polygon)
|
|
BGCALL(result, within, Multipolygon, g1, Polygon, g2, pnull_value);
|
|
else if (gt2 == Geometry::wkb_multipolygon)
|
|
BGCALL(result, within, Multipolygon, g1, Multipolygon, g2, pnull_value);
|
|
else if (gt2 == Geometry::wkb_point || gt2 == Geometry::wkb_multipoint ||
|
|
gt2 == Geometry::wkb_linestring ||
|
|
gt2 == Geometry::wkb_multilinestring)
|
|
return 0;
|
|
else
|
|
DBUG_ASSERT(false);
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
Dispatcher for 'multipoint EQUALS xxx'.
|
|
|
|
@tparam Geom_types Geometry types definitions.
|
|
@param g1 First Geometry operand, a multipoint.
|
|
@param g2 Second Geometry operand, not a geometry collection.
|
|
@param[out] pnull_value Returns whether error occurred duirng the computation.
|
|
@return 0 if specified relation doesn't hold for the given operands,
|
|
otherwise returns none 0.
|
|
*/
|
|
template <typename Geom_types>
|
|
int BG_wrap<Geom_types>::multipoint_equals_geometry(Geometry *g1, Geometry *g2,
|
|
bool *pnull_value) {
|
|
int result = 0;
|
|
Geometry::wkbType gt2 = g2->get_type();
|
|
|
|
switch (gt2) {
|
|
case Geometry::wkb_point:
|
|
result = Ifsr::equals_check<Geom_types>(g2, g1, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multipoint: {
|
|
Multipoint mpts1(g1->get_data_ptr(), g1->get_data_size(), g1->get_flags(),
|
|
g1->get_srid());
|
|
Multipoint mpts2(g2->get_data_ptr(), g2->get_data_size(), g2->get_flags(),
|
|
g2->get_srid());
|
|
|
|
Point_set ptset1(mpts1.begin(), mpts1.end());
|
|
Point_set ptset2(mpts2.begin(), mpts2.end());
|
|
result =
|
|
(ptset1.size() == ptset2.size() &&
|
|
std::equal(ptset1.begin(), ptset1.end(), ptset2.begin(), bgpt_eq()));
|
|
} break;
|
|
default:
|
|
result = 0;
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
Dispatcher for 'multipoint disjoint xxx'.
|
|
|
|
@tparam Geom_types Geometry types definitions.
|
|
@param g1 First Geometry operand, a multipoint.
|
|
@param g2 Second Geometry operand, not a geometry collection.
|
|
@param[out] pnull_value Returns whether error occurred duirng the computation.
|
|
@return 0 if specified relation doesn't hold for the given operands,
|
|
otherwise returns none 0.
|
|
*/
|
|
template <typename Geom_types>
|
|
int BG_wrap<Geom_types>::multipoint_disjoint_geometry(Geometry *g1,
|
|
Geometry *g2,
|
|
bool *pnull_value) {
|
|
int result = 0;
|
|
Geometry::wkbType gt2 = g2->get_type();
|
|
const void *data_ptr = NULL;
|
|
|
|
Multipoint mpts1(g1->get_data_ptr(), g1->get_data_size(), g1->get_flags(),
|
|
g1->get_srid());
|
|
switch (gt2) {
|
|
case Geometry::wkb_point:
|
|
result = point_disjoint_geometry(g2, g1, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multipoint: {
|
|
Multipoint mpts2(g2->get_data_ptr(), g2->get_data_size(), g2->get_flags(),
|
|
g2->get_srid());
|
|
Point_set ptset1(mpts1.begin(), mpts1.end());
|
|
Point_set ptset2(mpts2.begin(), mpts2.end());
|
|
Point_vector respts;
|
|
typename Point_vector::iterator endpos;
|
|
size_t ptset1sz = ptset1.size(), ptset2sz = ptset2.size();
|
|
|
|
respts.resize(ptset1sz > ptset2sz ? ptset1sz : ptset2sz);
|
|
endpos =
|
|
std::set_intersection(ptset1.begin(), ptset1.end(), ptset2.begin(),
|
|
ptset2.end(), respts.begin(), bgpt_lt());
|
|
result = (endpos == respts.begin());
|
|
} break;
|
|
case Geometry::wkb_polygon: {
|
|
data_ptr = g2->normalize_ring_order();
|
|
if (data_ptr == NULL) {
|
|
*pnull_value = true;
|
|
my_error(ER_GIS_INVALID_DATA, MYF(0), "st_disjoint");
|
|
return result;
|
|
}
|
|
|
|
Polygon plg(data_ptr, g2->get_data_size(), g2->get_flags(),
|
|
g2->get_srid());
|
|
result = multipoint_disjoint_geometry_internal(mpts1, plg);
|
|
} break;
|
|
case Geometry::wkb_multipolygon: {
|
|
data_ptr = g2->normalize_ring_order();
|
|
if (data_ptr == NULL) {
|
|
*pnull_value = true;
|
|
my_error(ER_GIS_INVALID_DATA, MYF(0), "st_disjoint");
|
|
return result;
|
|
}
|
|
|
|
Multipolygon mplg(data_ptr, g2->get_data_size(), g2->get_flags(),
|
|
g2->get_srid());
|
|
result = multipoint_disjoint_multi_geometry(mpts1, mplg);
|
|
} break;
|
|
case Geometry::wkb_linestring: {
|
|
Linestring ls(g2->get_data_ptr(), g2->get_data_size(), g2->get_flags(),
|
|
g2->get_srid());
|
|
result = multipoint_disjoint_geometry_internal(mpts1, ls);
|
|
} break;
|
|
case Geometry::wkb_multilinestring: {
|
|
Multilinestring mls(g2->get_data_ptr(), g2->get_data_size(),
|
|
g2->get_flags(), g2->get_srid());
|
|
result = multipoint_disjoint_multi_geometry(mpts1, mls);
|
|
} break;
|
|
default:
|
|
DBUG_ASSERT(false);
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
template <typename Geom_types>
|
|
template <typename Geom_type>
|
|
int BG_wrap<Geom_types>::multipoint_disjoint_geometry_internal(
|
|
const Multipoint &mpts, const Geom_type &geom) {
|
|
for (typename Multipoint::iterator i = mpts.begin(); i != mpts.end(); ++i) {
|
|
if (!boost::geometry::disjoint(*i, geom)) return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
template <typename Geom_types>
|
|
template <typename Geom_type>
|
|
int BG_wrap<Geom_types>::multipoint_disjoint_multi_geometry(
|
|
const Multipoint &mpts, const Geom_type &geom) {
|
|
Rtree_index rtree;
|
|
|
|
// Choose the one with more components to build rtree index on, to get more
|
|
// performance improvement.
|
|
if (mpts.size() > geom.size()) {
|
|
make_rtree_bggeom(mpts, &rtree);
|
|
for (typename Geom_type::iterator j = geom.begin(); j != geom.end(); ++j) {
|
|
BG_box box;
|
|
boost::geometry::envelope(*j, box);
|
|
|
|
/*
|
|
For each component *j in geom, find points in mpts who intersect
|
|
with MBR(*j), such points are likely to intersect *j, the rest are
|
|
for sure disjoint *j thus no need to check precisely.
|
|
*/
|
|
for (Rtree_index::const_query_iterator i =
|
|
rtree.qbegin(bgi::intersects(box));
|
|
i != rtree.qend(); ++i) {
|
|
/*
|
|
If *i really intersect *j, we have the result as false;
|
|
If no *i intersects *j, *j disjoint mpts.
|
|
And if no *j intersect mpts, we can conclude that mpts disjoint geom.
|
|
*/
|
|
if (!boost::geometry::disjoint(mpts[i->second], *j)) return 0;
|
|
}
|
|
}
|
|
} else {
|
|
make_rtree_bggeom(geom, &rtree);
|
|
for (typename Multipoint::iterator j = mpts.begin(); j != mpts.end(); ++j) {
|
|
BG_box box;
|
|
boost::geometry::envelope(*j, box);
|
|
|
|
/*
|
|
For each point *j in mpts, find components *i in geom such that
|
|
MBR(*i) intersect *j, such *i are likely to intersect *j, the rest are
|
|
for sure disjoint *j thus no need to check precisely.
|
|
*/
|
|
for (Rtree_index::const_query_iterator i =
|
|
rtree.qbegin(bgi::intersects(box));
|
|
i != rtree.qend(); ++i) {
|
|
/*
|
|
If *i really intersect *j, we have the result as false;
|
|
If no *i intersects *j, *j disjoint geom.
|
|
And if no *j intersect geom, we can conclude that mpts disjoint geom.
|
|
*/
|
|
if (!boost::geometry::disjoint(geom[i->second], *j)) return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
Dispatcher for 'linestring disjoint xxx'.
|
|
|
|
@tparam Geom_types Geometry types definitions.
|
|
@param g1 First Geometry operand, a linestring.
|
|
@param g2 Second Geometry operand, not a geometry collection.
|
|
@param[out] pnull_value Returns whether error occurred duirng the computation.
|
|
@return 0 if specified relation doesn't hold for the given operands,
|
|
otherwise returns none 0.
|
|
*/
|
|
template <typename Geom_types>
|
|
int BG_wrap<Geom_types>::linestring_disjoint_geometry(Geometry *g1,
|
|
Geometry *g2,
|
|
bool *pnull_value) {
|
|
int result = 0;
|
|
Geometry::wkbType gt2 = g2->get_type();
|
|
|
|
if (gt2 == Geometry::wkb_linestring)
|
|
BGCALL(result, disjoint, Linestring, g1, Linestring, g2, pnull_value);
|
|
else if (gt2 == Geometry::wkb_multilinestring)
|
|
BGCALL(result, disjoint, Linestring, g1, Multilinestring, g2, pnull_value);
|
|
else if (gt2 == Geometry::wkb_point)
|
|
BGCALL(result, disjoint, Linestring, g1, Point, g2, pnull_value);
|
|
else if (gt2 == Geometry::wkb_multipoint)
|
|
result = multipoint_disjoint_geometry(g2, g1, pnull_value);
|
|
else if (gt2 == Geometry::wkb_polygon)
|
|
BGCALL(result, disjoint, Linestring, g1, Polygon, g2, pnull_value);
|
|
else if (gt2 == Geometry::wkb_multipolygon)
|
|
BGCALL(result, disjoint, Linestring, g1, Multipolygon, g2, pnull_value);
|
|
else
|
|
DBUG_ASSERT(false);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
Dispatcher for 'multilinestring disjoint xxx'.
|
|
|
|
@tparam Geom_types Geometry types definitions.
|
|
@param g1 First Geometry operand, a multilinestring.
|
|
@param g2 Second Geometry operand, not a geometry collection.
|
|
@param[out] pnull_value Returns whether error occurred duirng the computation.
|
|
@return 0 if specified relation doesn't hold for the given operands,
|
|
otherwise returns none 0.
|
|
*/
|
|
template <typename Geom_types>
|
|
int BG_wrap<Geom_types>::multilinestring_disjoint_geometry(Geometry *g1,
|
|
Geometry *g2,
|
|
bool *pnull_value) {
|
|
int result = 0;
|
|
Geometry::wkbType gt2 = g2->get_type();
|
|
|
|
if (gt2 == Geometry::wkb_linestring)
|
|
result =
|
|
BG_wrap<Geom_types>::linestring_disjoint_geometry(g2, g1, pnull_value);
|
|
else if (gt2 == Geometry::wkb_multilinestring)
|
|
BGCALL(result, disjoint, Multilinestring, g1, Multilinestring, g2,
|
|
pnull_value);
|
|
else if (gt2 == Geometry::wkb_point)
|
|
BGCALL(result, disjoint, Multilinestring, g1, Point, g2, pnull_value);
|
|
else if (gt2 == Geometry::wkb_multipoint)
|
|
result = multipoint_disjoint_geometry(g2, g1, pnull_value);
|
|
else if (gt2 == Geometry::wkb_polygon)
|
|
BGCALL(result, disjoint, Multilinestring, g1, Polygon, g2, pnull_value);
|
|
else if (gt2 == Geometry::wkb_multipolygon)
|
|
BGCALL(result, disjoint, Multilinestring, g1, Multipolygon, g2,
|
|
pnull_value);
|
|
else
|
|
DBUG_ASSERT(false);
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
Dispatcher for 'point disjoint xxx'.
|
|
|
|
@tparam Geom_types Geometry types definitions.
|
|
@param g1 First Geometry operand, a point.
|
|
@param g2 Second Geometry operand, not a geometry collection.
|
|
@param[out] pnull_value Returns whether error occurred duirng the computation.
|
|
@return 0 if specified relation doesn't hold for the given operands,
|
|
otherwise returns none 0.
|
|
*/
|
|
template <typename Geom_types>
|
|
int BG_wrap<Geom_types>::point_disjoint_geometry(Geometry *g1, Geometry *g2,
|
|
bool *pnull_value) {
|
|
int result = 0;
|
|
Geometry::wkbType gt2 = g2->get_type();
|
|
|
|
switch (gt2) {
|
|
case Geometry::wkb_point:
|
|
BGCALL(result, disjoint, Point, g1, Point, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_polygon:
|
|
BGCALL(result, disjoint, Point, g1, Polygon, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multipolygon:
|
|
BGCALL(result, disjoint, Point, g1, Multipolygon, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multipoint: {
|
|
Multipoint mpts(g2->get_data_ptr(), g2->get_data_size(), g2->get_flags(),
|
|
g2->get_srid());
|
|
Point pt(g1->get_data_ptr(), g1->get_data_size(), g1->get_flags(),
|
|
g1->get_srid());
|
|
|
|
Point_set ptset(mpts.begin(), mpts.end());
|
|
result = (ptset.find(pt) == ptset.end());
|
|
} break;
|
|
case Geometry::wkb_linestring:
|
|
BGCALL(result, disjoint, Point, g1, Linestring, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multilinestring:
|
|
BGCALL(result, disjoint, Point, g1, Multilinestring, g2, pnull_value);
|
|
break;
|
|
default:
|
|
DBUG_ASSERT(false);
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
Dispatcher for 'polygon disjoint xxx'.
|
|
|
|
@tparam Geom_types Geometry types definitions.
|
|
@param g1 First Geometry operand, a polygon.
|
|
@param g2 Second Geometry operand, not a geometry collection.
|
|
@param[out] pnull_value Returns whether error occurred duirng the computation.
|
|
@return 0 if specified relation doesn't hold for the given operands,
|
|
otherwise returns none 0.
|
|
*/
|
|
template <typename Geom_types>
|
|
int BG_wrap<Geom_types>::polygon_disjoint_geometry(Geometry *g1, Geometry *g2,
|
|
bool *pnull_value) {
|
|
int result = 0;
|
|
Geometry::wkbType gt2 = g2->get_type();
|
|
|
|
switch (gt2) {
|
|
case Geometry::wkb_point:
|
|
BGCALL(result, disjoint, Polygon, g1, Point, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multipoint:
|
|
result = multipoint_disjoint_geometry(g2, g1, pnull_value);
|
|
break;
|
|
case Geometry::wkb_polygon:
|
|
BGCALL(result, disjoint, Polygon, g1, Polygon, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multipolygon:
|
|
BGCALL(result, disjoint, Polygon, g1, Multipolygon, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_linestring:
|
|
BGCALL(result, disjoint, Polygon, g1, Linestring, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multilinestring:
|
|
BGCALL(result, disjoint, Polygon, g1, Multilinestring, g2, pnull_value);
|
|
break;
|
|
default:
|
|
DBUG_ASSERT(false);
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
Dispatcher for 'multipolygon disjoint xxx'.
|
|
|
|
@tparam Geom_types Geometry types definitions.
|
|
@param g1 First Geometry operand, a multipolygon.
|
|
@param g2 Second Geometry operand, not a geometry collection.
|
|
@param[out] pnull_value Returns whether error occurred duirng the computation.
|
|
@return 0 if specified relation doesn't hold for the given operands,
|
|
otherwise returns none 0.
|
|
*/
|
|
template <typename Geom_types>
|
|
int BG_wrap<Geom_types>::multipolygon_disjoint_geometry(Geometry *g1,
|
|
Geometry *g2,
|
|
bool *pnull_value) {
|
|
int result = 0;
|
|
Geometry::wkbType gt2 = g2->get_type();
|
|
|
|
switch (gt2) {
|
|
case Geometry::wkb_point:
|
|
BGCALL(result, disjoint, Multipolygon, g1, Point, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multipoint:
|
|
result = multipoint_disjoint_geometry(g2, g1, pnull_value);
|
|
break;
|
|
case Geometry::wkb_polygon:
|
|
BGCALL(result, disjoint, Multipolygon, g1, Polygon, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multipolygon:
|
|
BGCALL(result, disjoint, Multipolygon, g1, Multipolygon, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_linestring:
|
|
BGCALL(result, disjoint, Multipolygon, g1, Linestring, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multilinestring:
|
|
BGCALL(result, disjoint, Multipolygon, g1, Multilinestring, g2,
|
|
pnull_value);
|
|
break;
|
|
default:
|
|
DBUG_ASSERT(false);
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
Dispatcher for 'point intersects xxx'.
|
|
|
|
@tparam Geom_types Geometry types definitions.
|
|
@param g1 First Geometry operand, a point.
|
|
@param g2 Second Geometry operand, not a geometry collection.
|
|
@param[out] pnull_value Returns whether error occurred duirng the computation.
|
|
@return 0 if specified relation doesn't hold for the given operands,
|
|
otherwise returns none 0.
|
|
*/
|
|
template <typename Geom_types>
|
|
int BG_wrap<Geom_types>::point_intersects_geometry(Geometry *g1, Geometry *g2,
|
|
bool *pnull_value) {
|
|
int result = 0;
|
|
Geometry::wkbType gt2 = g2->get_type();
|
|
|
|
switch (gt2) {
|
|
case Geometry::wkb_point:
|
|
BGCALL(result, intersects, Point, g1, Point, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multipoint:
|
|
case Geometry::wkb_linestring:
|
|
case Geometry::wkb_multilinestring:
|
|
result = !point_disjoint_geometry(g1, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_polygon:
|
|
BGCALL(result, intersects, Point, g1, Polygon, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multipolygon:
|
|
BGCALL(result, intersects, Point, g1, Multipolygon, g2, pnull_value);
|
|
break;
|
|
default:
|
|
DBUG_ASSERT(false);
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
Dispatcher for 'multipoint intersects xxx'.
|
|
|
|
@tparam Geom_types Geometry types definitions.
|
|
@param g1 First Geometry operand, a multipoint.
|
|
@param g2 Second Geometry operand, not a geometry collection.
|
|
@param[out] pnull_value Returns whether error occurred duirng the computation.
|
|
@return 0 if specified relation doesn't hold for the given operands,
|
|
otherwise returns none 0.
|
|
*/
|
|
template <typename Geom_types>
|
|
int BG_wrap<Geom_types>::multipoint_intersects_geometry(Geometry *g1,
|
|
Geometry *g2,
|
|
bool *pnull_value) {
|
|
return !multipoint_disjoint_geometry(g1, g2, pnull_value);
|
|
}
|
|
|
|
/**
|
|
Dispatcher for 'linestring intersects xxx'.
|
|
|
|
@tparam Geom_types Geometry types definitions.
|
|
@param g1 First Geometry operand, a linestring.
|
|
@param g2 Second Geometry operand, not a geometry collection.
|
|
@param[out] pnull_value Returns whether error occurred duirng the computation.
|
|
@return 0 if specified relation doesn't hold for the given operands,
|
|
otherwise returns none 0.
|
|
*/
|
|
template <typename Geom_types>
|
|
int BG_wrap<Geom_types>::linestring_intersects_geometry(Geometry *g1,
|
|
Geometry *g2,
|
|
bool *pnull_value) {
|
|
int result = 0;
|
|
Geometry::wkbType gt2 = g2->get_type();
|
|
|
|
if (gt2 == Geometry::wkb_point)
|
|
BGCALL(result, intersects, Linestring, g1, Point, g2, pnull_value);
|
|
else if (gt2 == Geometry::wkb_multipoint)
|
|
result = multipoint_intersects_geometry(g2, g1, pnull_value);
|
|
else if (gt2 == Geometry::wkb_linestring)
|
|
BGCALL(result, intersects, Linestring, g1, Linestring, g2, pnull_value);
|
|
else if (gt2 == Geometry::wkb_multilinestring)
|
|
BGCALL(result, intersects, Linestring, g1, Multilinestring, g2,
|
|
pnull_value);
|
|
else if (gt2 == Geometry::wkb_polygon)
|
|
BGCALL(result, intersects, Linestring, g1, Polygon, g2, pnull_value);
|
|
else if (gt2 == Geometry::wkb_multipolygon)
|
|
BGCALL(result, intersects, Linestring, g1, Multipolygon, g2, pnull_value);
|
|
else
|
|
DBUG_ASSERT(false);
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
Dispatcher for 'multilinestring intersects xxx'.
|
|
|
|
@tparam Geom_types Geometry types definitions.
|
|
@param g1 First Geometry operand, a multilinestring.
|
|
@param g2 Second Geometry operand, not a geometry collection.
|
|
@param[out] pnull_value Returns whether error occurred duirng the computation.
|
|
@return 0 if specified relation doesn't hold for the given operands,
|
|
otherwise returns none 0.
|
|
*/
|
|
template <typename Geom_types>
|
|
int BG_wrap<Geom_types>::multilinestring_intersects_geometry(
|
|
Geometry *g1, Geometry *g2, bool *pnull_value) {
|
|
int result = 0;
|
|
Geometry::wkbType gt2 = g2->get_type();
|
|
|
|
if (gt2 == Geometry::wkb_point)
|
|
BGCALL(result, intersects, Multilinestring, g1, Point, g2, pnull_value);
|
|
else if (gt2 == Geometry::wkb_multipoint)
|
|
result = multipoint_intersects_geometry(g2, g1, pnull_value);
|
|
else if (gt2 == Geometry::wkb_linestring)
|
|
BGCALL(result, intersects, Multilinestring, g1, Linestring, g2,
|
|
pnull_value);
|
|
else if (gt2 == Geometry::wkb_multilinestring)
|
|
BGCALL(result, intersects, Multilinestring, g1, Multilinestring, g2,
|
|
pnull_value);
|
|
else if (gt2 == Geometry::wkb_polygon)
|
|
BGCALL(result, intersects, Multilinestring, g1, Polygon, g2, pnull_value);
|
|
else if (gt2 == Geometry::wkb_multipolygon)
|
|
BGCALL(result, intersects, Multilinestring, g1, Multipolygon, g2,
|
|
pnull_value);
|
|
else
|
|
DBUG_ASSERT(false);
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
Dispatcher for 'polygon intersects xxx'.
|
|
|
|
@tparam Geom_types Geometry types definitions.
|
|
@param g1 First Geometry operand, a polygon.
|
|
@param g2 Second Geometry operand, not a geometry collection.
|
|
@param[out] pnull_value Returns whether error occurred duirng the computation.
|
|
@return 0 if specified relation doesn't hold for the given operands,
|
|
otherwise returns none 0.
|
|
*/
|
|
template <typename Geom_types>
|
|
int BG_wrap<Geom_types>::polygon_intersects_geometry(Geometry *g1, Geometry *g2,
|
|
bool *pnull_value) {
|
|
int result = 0;
|
|
Geometry::wkbType gt2 = g2->get_type();
|
|
|
|
switch (gt2) {
|
|
case Geometry::wkb_point:
|
|
BGCALL(result, intersects, Polygon, g1, Point, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multipoint:
|
|
result = !multipoint_disjoint_geometry(g2, g1, pnull_value);
|
|
break;
|
|
case Geometry::wkb_polygon:
|
|
BGCALL(result, intersects, Polygon, g1, Polygon, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multipolygon:
|
|
BGCALL(result, intersects, Polygon, g1, Multipolygon, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_linestring:
|
|
BGCALL(result, intersects, Polygon, g1, Linestring, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multilinestring:
|
|
BGCALL(result, intersects, Polygon, g1, Multilinestring, g2, pnull_value);
|
|
break;
|
|
default:
|
|
DBUG_ASSERT(false);
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
Dispatcher for 'multipolygon intersects xxx'.
|
|
|
|
@tparam Geom_types Geometry types definitions.
|
|
@param g1 First Geometry operand, a multipolygon.
|
|
@param g2 Second Geometry operand, not a geometry collection.
|
|
@param[out] pnull_value Returns whether error occurred duirng the computation.
|
|
@return 0 if specified relation doesn't hold for the given operands,
|
|
otherwise returns none 0.
|
|
*/
|
|
template <typename Geom_types>
|
|
int BG_wrap<Geom_types>::multipolygon_intersects_geometry(Geometry *g1,
|
|
Geometry *g2,
|
|
bool *pnull_value) {
|
|
int result = 0;
|
|
Geometry::wkbType gt2 = g2->get_type();
|
|
|
|
switch (gt2) {
|
|
case Geometry::wkb_point:
|
|
BGCALL(result, intersects, Multipolygon, g1, Point, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multipoint:
|
|
result = !multipoint_disjoint_geometry(g2, g1, pnull_value);
|
|
break;
|
|
case Geometry::wkb_polygon:
|
|
BGCALL(result, intersects, Multipolygon, g1, Polygon, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multipolygon:
|
|
BGCALL(result, intersects, Multipolygon, g1, Multipolygon, g2,
|
|
pnull_value);
|
|
break;
|
|
case Geometry::wkb_linestring:
|
|
BGCALL(result, intersects, Multipolygon, g1, Linestring, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multilinestring:
|
|
BGCALL(result, intersects, Multipolygon, g1, Multilinestring, g2,
|
|
pnull_value);
|
|
break;
|
|
default:
|
|
DBUG_ASSERT(false);
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
Dispatcher for 'linestring crosses xxx'.
|
|
|
|
@tparam Geom_types Geometry types definitions.
|
|
@param g1 First Geometry operand, a linestring.
|
|
@param g2 Second Geometry operand, not a geometry collection.
|
|
@param[out] pnull_value Returns whether error occurred duirng the computation.
|
|
@return 0 if specified relation doesn't hold for the given operands,
|
|
otherwise returns none 0.
|
|
*/
|
|
template <typename Geom_types>
|
|
int BG_wrap<Geom_types>::linestring_crosses_geometry(Geometry *g1, Geometry *g2,
|
|
bool *pnull_value) {
|
|
int result = 0;
|
|
Geometry::wkbType gt2 = g2->get_type();
|
|
|
|
switch (gt2) {
|
|
case Geometry::wkb_linestring:
|
|
BGCALL(result, crosses, Linestring, g1, Linestring, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multilinestring:
|
|
BGCALL(result, crosses, Linestring, g1, Multilinestring, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_polygon:
|
|
BGCALL(result, crosses, Linestring, g1, Polygon, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multipolygon:
|
|
BGCALL(result, crosses, Linestring, g1, Multipolygon, g2, pnull_value);
|
|
break;
|
|
default:
|
|
DBUG_ASSERT(false);
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
Dispatcher for 'multilinestring crosses xxx'.
|
|
|
|
@tparam Geom_types Geometry types definitions.
|
|
@param g1 First Geometry operand, a multilinestring.
|
|
@param g2 Second Geometry operand, not a geometry collection.
|
|
@param[out] pnull_value Returns whether error occurred duirng the computation.
|
|
@return 0 if specified relation doesn't hold for the given operands,
|
|
otherwise returns none 0.
|
|
*/
|
|
template <typename Geom_types>
|
|
int BG_wrap<Geom_types>::multilinestring_crosses_geometry(Geometry *g1,
|
|
Geometry *g2,
|
|
bool *pnull_value) {
|
|
int result = 0;
|
|
Geometry::wkbType gt2 = g2->get_type();
|
|
|
|
switch (gt2) {
|
|
case Geometry::wkb_linestring:
|
|
BGCALL(result, crosses, Multilinestring, g1, Linestring, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multilinestring:
|
|
BGCALL(result, crosses, Multilinestring, g1, Multilinestring, g2,
|
|
pnull_value);
|
|
break;
|
|
case Geometry::wkb_polygon:
|
|
BGCALL(result, crosses, Multilinestring, g1, Polygon, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multipolygon:
|
|
BGCALL(result, crosses, Multilinestring, g1, Multipolygon, g2,
|
|
pnull_value);
|
|
break;
|
|
default:
|
|
DBUG_ASSERT(false);
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
Dispatcher for 'multipoint crosses xxx'.
|
|
|
|
@tparam Geom_types Geometry types definitions.
|
|
@param g1 First Geometry operand, a multipoint.
|
|
@param g2 Second Geometry operand, not a geometry collection.
|
|
@param[out] pnull_value Returns whether error occurred duirng the computation.
|
|
@return 0 if specified relation doesn't hold for the given operands,
|
|
otherwise returns none 0.
|
|
*/
|
|
template <typename Geom_types>
|
|
int BG_wrap<Geom_types>::multipoint_crosses_geometry(Geometry *g1, Geometry *g2,
|
|
bool *pnull_value) {
|
|
int result = 0;
|
|
Geometry::wkbType gt2 = g2->get_type();
|
|
|
|
switch (gt2) {
|
|
case Geometry::wkb_linestring:
|
|
case Geometry::wkb_multilinestring:
|
|
case Geometry::wkb_polygon:
|
|
case Geometry::wkb_multipolygon: {
|
|
bool has_in = false, has_out = false;
|
|
int res = 0;
|
|
|
|
Multipoint mpts(g1->get_data_ptr(), g1->get_data_size(), g1->get_flags(),
|
|
g1->get_srid());
|
|
/*
|
|
According to OGC's definition to crosses, if some Points of
|
|
g1 is in g2 and some are not, g1 crosses g2, otherwise not.
|
|
*/
|
|
for (typename Multipoint::iterator i = mpts.begin();
|
|
i != mpts.end() && !(has_in && has_out); ++i) {
|
|
if (!has_out) {
|
|
res = point_disjoint_geometry(&(*i), g2, pnull_value);
|
|
|
|
if (!*pnull_value) {
|
|
has_out = res;
|
|
if (has_out) continue;
|
|
} else
|
|
return 0;
|
|
}
|
|
|
|
if (!has_in) {
|
|
res = point_within_geometry(&(*i), g2, pnull_value);
|
|
if (!*pnull_value)
|
|
has_in = res;
|
|
else
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
result = (has_in && has_out);
|
|
} break;
|
|
default:
|
|
DBUG_ASSERT(false);
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
Dispatcher for 'multipoint crosses xxx'.
|
|
|
|
@tparam Geom_types Geometry types definitions.
|
|
@param g1 First Geometry operand, a multipoint.
|
|
@param g2 Second Geometry operand, not a geometry collection.
|
|
@return 0 if specified relation doesn't hold for the given operands,
|
|
otherwise returns none 0.
|
|
*/
|
|
template <typename Geom_types>
|
|
int BG_wrap<Geom_types>::multipoint_overlaps_multipoint(Geometry *g1,
|
|
Geometry *g2) {
|
|
int result = 0;
|
|
|
|
Multipoint mpts1(g1->get_data_ptr(), g1->get_data_size(), g1->get_flags(),
|
|
g1->get_srid());
|
|
Multipoint mpts2(g2->get_data_ptr(), g2->get_data_size(), g2->get_flags(),
|
|
g2->get_srid());
|
|
Point_set ptset1, ptset2;
|
|
|
|
ptset1.insert(mpts1.begin(), mpts1.end());
|
|
ptset2.insert(mpts2.begin(), mpts2.end());
|
|
|
|
// They overlap if they intersect and also each has some points that the other
|
|
// one doesn't have.
|
|
Point_vector respts;
|
|
typename Point_vector::iterator endpos;
|
|
size_t ptset1sz = ptset1.size(), ptset2sz = ptset2.size(), resptssz;
|
|
|
|
respts.resize(ptset1sz > ptset2sz ? ptset1sz : ptset2sz);
|
|
endpos = std::set_intersection(ptset1.begin(), ptset1.end(), ptset2.begin(),
|
|
ptset2.end(), respts.begin(), bgpt_lt());
|
|
resptssz = endpos - respts.begin();
|
|
if (resptssz > 0 && resptssz < ptset1.size() && resptssz < ptset2.size())
|
|
result = 1;
|
|
else
|
|
result = 0;
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
Dispatcher for 'multilinestring touches polygon'.
|
|
|
|
@tparam Geom_types Geometry types definitions.
|
|
@param g1 First Geometry operand, a multilinestring.
|
|
@param g2 Second Geometry operand, a polygon.
|
|
@param[out] pnull_value Returns whether error occurred duirng the computation.
|
|
@return 0 if specified relation doesn't hold for the given operands,
|
|
otherwise returns none 0.
|
|
*/
|
|
template <typename Geom_types>
|
|
int BG_wrap<Geom_types>::multilinestring_touches_polygon(Geometry *g1,
|
|
Geometry *g2,
|
|
bool *pnull_value) {
|
|
const void *data_ptr = g2->normalize_ring_order();
|
|
if (data_ptr == NULL) {
|
|
*pnull_value = true;
|
|
my_error(ER_GIS_INVALID_DATA, MYF(0), "st_touches");
|
|
return 0;
|
|
}
|
|
|
|
Polygon plgn(data_ptr, g2->get_data_size(), g2->get_flags(), g2->get_srid());
|
|
Multilinestring mls(g1->get_data_ptr(), g1->get_data_size(), g1->get_flags(),
|
|
g1->get_srid());
|
|
|
|
Multipolygon mplgn;
|
|
mplgn.push_back(plgn);
|
|
|
|
int result = boost::geometry::touches(mls, mplgn);
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
Dispatcher for 'point touches geometry'.
|
|
|
|
@tparam Geom_types Geometry types definitions.
|
|
@param g1 First Geometry operand, a point.
|
|
@param g2 Second Geometry operand, a geometry other than geometry collection.
|
|
@param[out] pnull_value Returns whether error occurred duirng the computation.
|
|
@return 0 if specified relation doesn't hold for the given operands,
|
|
otherwise returns none 0.
|
|
*/
|
|
template <typename Geom_types>
|
|
int BG_wrap<Geom_types>::point_touches_geometry(Geometry *g1, Geometry *g2,
|
|
bool *pnull_value) {
|
|
int result = 0;
|
|
Geometry::wkbType gt2 = g2->get_type();
|
|
|
|
switch (gt2) {
|
|
case Geometry::wkb_linestring:
|
|
BGCALL(result, touches, Point, g1, Linestring, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multilinestring:
|
|
BGCALL(result, touches, Point, g1, Multilinestring, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_polygon:
|
|
BGCALL(result, touches, Point, g1, Polygon, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multipolygon:
|
|
BGCALL(result, touches, Point, g1, Multipolygon, g2, pnull_value);
|
|
break;
|
|
default:
|
|
DBUG_ASSERT(false);
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
Dispatcher for 'multipoint touches geometry'.
|
|
|
|
@tparam Geom_types Geometry types definitions.
|
|
@param g1 First Geometry operand, a multipoint.
|
|
@param g2 Second Geometry operand, a geometry other than geometry collection.
|
|
@param[out] pnull_value Returns whether error occurred duirng the computation.
|
|
@return 0 if specified relation doesn't hold for the given operands,
|
|
otherwise returns none 0.
|
|
*/
|
|
template <typename Geom_types>
|
|
int BG_wrap<Geom_types>::multipoint_touches_geometry(Geometry *g1, Geometry *g2,
|
|
bool *pnull_value) {
|
|
int has_touches = 0;
|
|
|
|
Multipoint mpts(g1->get_data_ptr(), g1->get_data_size(), g1->get_flags(),
|
|
g1->get_srid());
|
|
for (typename Multipoint::iterator i = mpts.begin(); i != mpts.end(); ++i) {
|
|
int ptg = point_touches_geometry(&(*i), g2, pnull_value);
|
|
if (*pnull_value) return 0;
|
|
if (ptg)
|
|
has_touches = 1;
|
|
else if (!point_disjoint_geometry(&(*i), g2, pnull_value))
|
|
return 0;
|
|
}
|
|
|
|
return has_touches;
|
|
}
|
|
|
|
/**
|
|
Dispatcher for 'linestring touches geometry'.
|
|
|
|
@tparam Geom_types Geometry types definitions.
|
|
@param g1 First Geometry operand, a linestring.
|
|
@param g2 Second Geometry operand, a geometry other than geometry collection.
|
|
@param[out] pnull_value Returns whether error occurred duirng the computation.
|
|
@return 0 if specified relation doesn't hold for the given operands,
|
|
otherwise returns none 0.
|
|
*/
|
|
template <typename Geom_types>
|
|
int BG_wrap<Geom_types>::linestring_touches_geometry(Geometry *g1, Geometry *g2,
|
|
bool *pnull_value) {
|
|
int result = 0;
|
|
Geometry::wkbType gt2 = g2->get_type();
|
|
|
|
switch (gt2) {
|
|
case Geometry::wkb_point:
|
|
BGCALL(result, touches, Linestring, g1, Point, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multipoint:
|
|
result = multipoint_touches_geometry(g2, g1, pnull_value);
|
|
break;
|
|
case Geometry::wkb_linestring:
|
|
BGCALL(result, touches, Linestring, g1, Linestring, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multilinestring:
|
|
BGCALL(result, touches, Linestring, g1, Multilinestring, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_polygon:
|
|
BGCALL(result, touches, Linestring, g1, Polygon, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multipolygon:
|
|
BGCALL(result, touches, Linestring, g1, Multipolygon, g2, pnull_value);
|
|
break;
|
|
default:
|
|
DBUG_ASSERT(false);
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
Dispatcher for 'multilinestring touches geometry'.
|
|
|
|
@tparam Geom_types Geometry types definitions.
|
|
@param g1 First Geometry operand, a multilinestring.
|
|
@param g2 Second Geometry operand, a geometry other than geometry collection.
|
|
@param[out] pnull_value Returns whether error occurred duirng the computation.
|
|
@return 0 if specified relation doesn't hold for the given operands,
|
|
otherwise returns none 0.
|
|
*/
|
|
template <typename Geom_types>
|
|
int BG_wrap<Geom_types>::multilinestring_touches_geometry(Geometry *g1,
|
|
Geometry *g2,
|
|
bool *pnull_value) {
|
|
int result = 0;
|
|
Geometry::wkbType gt2 = g2->get_type();
|
|
|
|
switch (gt2) {
|
|
case Geometry::wkb_point:
|
|
BGCALL(result, touches, Multilinestring, g1, Point, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multipoint:
|
|
result = multipoint_touches_geometry(g2, g1, pnull_value);
|
|
break;
|
|
case Geometry::wkb_linestring:
|
|
BGCALL(result, touches, Multilinestring, g1, Linestring, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multilinestring:
|
|
BGCALL(result, touches, Multilinestring, g1, Multilinestring, g2,
|
|
pnull_value);
|
|
break;
|
|
case Geometry::wkb_polygon:
|
|
result = BG_wrap<Geom_types>::multilinestring_touches_polygon(
|
|
g1, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multipolygon:
|
|
BGCALL(result, touches, Multilinestring, g1, Multipolygon, g2,
|
|
pnull_value);
|
|
break;
|
|
default:
|
|
DBUG_ASSERT(false);
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
Dispatcher for 'polygon touches geometry'.
|
|
|
|
@tparam Geom_types Geometry types definitions.
|
|
@param g1 First Geometry operand, a polygon.
|
|
@param g2 Second Geometry operand, a geometry other than geometry collection.
|
|
@param[out] pnull_value Returns whether error occurred duirng the computation.
|
|
@return 0 if specified relation doesn't hold for the given operands,
|
|
otherwise returns none 0.
|
|
*/
|
|
template <typename Geom_types>
|
|
int BG_wrap<Geom_types>::polygon_touches_geometry(Geometry *g1, Geometry *g2,
|
|
bool *pnull_value) {
|
|
int result = 0;
|
|
Geometry::wkbType gt2 = g2->get_type();
|
|
|
|
switch (gt2) {
|
|
case Geometry::wkb_point:
|
|
BGCALL(result, touches, Polygon, g1, Point, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multipoint:
|
|
result = multipoint_touches_geometry(g2, g1, pnull_value);
|
|
break;
|
|
case Geometry::wkb_polygon:
|
|
BGCALL(result, touches, Polygon, g1, Polygon, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multipolygon:
|
|
BGCALL(result, touches, Polygon, g1, Multipolygon, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_linestring:
|
|
BGCALL(result, touches, Polygon, g1, Linestring, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multilinestring:
|
|
result = BG_wrap<Geom_types>::multilinestring_touches_polygon(
|
|
g2, g1, pnull_value);
|
|
break;
|
|
default:
|
|
DBUG_ASSERT(false);
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
Dispatcher for 'multipolygon touches geometry'.
|
|
|
|
@tparam Geom_types Geometry types definitions.
|
|
@param g1 First Geometry operand, a multipolygon.
|
|
@param g2 Second Geometry operand, a geometry other than geometry collection.
|
|
@param[out] pnull_value Returns whether error occurred duirng the computation.
|
|
@return 0 if specified relation doesn't hold for the given operands,
|
|
otherwise returns none 0.
|
|
*/
|
|
template <typename Geom_types>
|
|
int BG_wrap<Geom_types>::multipolygon_touches_geometry(Geometry *g1,
|
|
Geometry *g2,
|
|
bool *pnull_value) {
|
|
int result = 0;
|
|
Geometry::wkbType gt2 = g2->get_type();
|
|
|
|
switch (gt2) {
|
|
case Geometry::wkb_point:
|
|
BGCALL(result, touches, Multipolygon, g1, Point, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multipoint:
|
|
result = multipoint_touches_geometry(g2, g1, pnull_value);
|
|
break;
|
|
case Geometry::wkb_polygon:
|
|
BGCALL(result, touches, Multipolygon, g1, Polygon, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multipolygon:
|
|
BGCALL(result, touches, Multipolygon, g1, Multipolygon, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_linestring:
|
|
BGCALL(result, touches, Multipolygon, g1, Linestring, g2, pnull_value);
|
|
break;
|
|
case Geometry::wkb_multilinestring:
|
|
BGCALL(result, touches, Multipolygon, g1, Multilinestring, g2,
|
|
pnull_value);
|
|
break;
|
|
default:
|
|
DBUG_ASSERT(false);
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
Explicit template instantiations are needed here.
|
|
Templates were moved to separate file in order to avoid
|
|
inlining and out-of-memory problems in optmized mode on gcc/solaris/intel.
|
|
*/
|
|
template int
|
|
BG_wrap<BG_models<boost::geometry::cs::cartesian>>::point_within_geometry(
|
|
Geometry *g1, Geometry *g2, bool *pnull_value);
|
|
template int
|
|
BG_wrap<BG_models<boost::geometry::cs::cartesian>>::multipoint_within_geometry(
|
|
Geometry *g1, Geometry *g2, bool *pnull_value);
|
|
template int
|
|
BG_wrap<BG_models<boost::geometry::cs::cartesian>>::linestring_within_geometry(
|
|
Geometry *g1, Geometry *g2, bool *pnull_value);
|
|
template int BG_wrap<BG_models<boost::geometry::cs::cartesian>>::
|
|
multilinestring_within_geometry(Geometry *g1, Geometry *g2,
|
|
bool *pnull_value);
|
|
template int
|
|
BG_wrap<BG_models<boost::geometry::cs::cartesian>>::polygon_within_geometry(
|
|
Geometry *g1, Geometry *g2, bool *pnull_value);
|
|
template int BG_wrap<BG_models<boost::geometry::cs::cartesian>>::
|
|
multipolygon_within_geometry(Geometry *g1, Geometry *g2, bool *pnull_value);
|
|
template int
|
|
BG_wrap<BG_models<boost::geometry::cs::cartesian>>::multipoint_equals_geometry(
|
|
Geometry *g1, Geometry *g2, bool *pnull_value);
|
|
template int
|
|
BG_wrap<BG_models<boost::geometry::cs::cartesian>>::point_disjoint_geometry(
|
|
Geometry *g1, Geometry *g2, bool *pnull_value);
|
|
template int BG_wrap<BG_models<boost::geometry::cs::cartesian>>::
|
|
multipoint_disjoint_geometry(Geometry *g1, Geometry *g2, bool *pnull_value);
|
|
template int BG_wrap<BG_models<boost::geometry::cs::cartesian>>::
|
|
linestring_disjoint_geometry(Geometry *g1, Geometry *g2, bool *pnull_value);
|
|
template int BG_wrap<BG_models<boost::geometry::cs::cartesian>>::
|
|
multilinestring_disjoint_geometry(Geometry *g1, Geometry *g2,
|
|
bool *pnull_value);
|
|
template int
|
|
BG_wrap<BG_models<boost::geometry::cs::cartesian>>::polygon_disjoint_geometry(
|
|
Geometry *g1, Geometry *g2, bool *pnull_value);
|
|
template int BG_wrap<BG_models<boost::geometry::cs::cartesian>>::
|
|
multipolygon_disjoint_geometry(Geometry *g1, Geometry *g2,
|
|
bool *pnull_value);
|
|
template int
|
|
BG_wrap<BG_models<boost::geometry::cs::cartesian>>::point_intersects_geometry(
|
|
Geometry *g1, Geometry *g2, bool *pnull_value);
|
|
template int BG_wrap<BG_models<boost::geometry::cs::cartesian>>::
|
|
multipoint_intersects_geometry(Geometry *g1, Geometry *g2,
|
|
bool *pnull_value);
|
|
template int BG_wrap<BG_models<boost::geometry::cs::cartesian>>::
|
|
linestring_intersects_geometry(Geometry *g1, Geometry *g2,
|
|
bool *pnull_value);
|
|
template int BG_wrap<BG_models<boost::geometry::cs::cartesian>>::
|
|
multilinestring_intersects_geometry(Geometry *g1, Geometry *g2,
|
|
bool *pnull_value);
|
|
template int
|
|
BG_wrap<BG_models<boost::geometry::cs::cartesian>>::polygon_intersects_geometry(
|
|
Geometry *g1, Geometry *g2, bool *pnull_value);
|
|
template int BG_wrap<BG_models<boost::geometry::cs::cartesian>>::
|
|
multipolygon_intersects_geometry(Geometry *g1, Geometry *g2,
|
|
bool *pnull_value);
|
|
template int
|
|
BG_wrap<BG_models<boost::geometry::cs::cartesian>>::linestring_crosses_geometry(
|
|
Geometry *g1, Geometry *g2, bool *pnull_value);
|
|
template int
|
|
BG_wrap<BG_models<boost::geometry::cs::cartesian>>::multipoint_crosses_geometry(
|
|
Geometry *g1, Geometry *g2, bool *pnull_value);
|
|
template int BG_wrap<BG_models<boost::geometry::cs::cartesian>>::
|
|
multilinestring_crosses_geometry(Geometry *g1, Geometry *g2,
|
|
bool *pnull_value);
|
|
template int BG_wrap<BG_models<boost::geometry::cs::cartesian>>::
|
|
multipoint_overlaps_multipoint(Geometry *g1, Geometry *g2);
|
|
template int
|
|
BG_wrap<BG_models<boost::geometry::cs::cartesian>>::point_touches_geometry(
|
|
Geometry *g1, Geometry *g2, bool *pnull_value);
|
|
template int
|
|
BG_wrap<BG_models<boost::geometry::cs::cartesian>>::multipoint_touches_geometry(
|
|
Geometry *g1, Geometry *g2, bool *pnull_value);
|
|
template int
|
|
BG_wrap<BG_models<boost::geometry::cs::cartesian>>::linestring_touches_geometry(
|
|
Geometry *g1, Geometry *g2, bool *pnull_value);
|
|
template int BG_wrap<BG_models<boost::geometry::cs::cartesian>>::
|
|
multilinestring_touches_polygon(Geometry *g1, Geometry *g2,
|
|
bool *pnull_value);
|
|
template int BG_wrap<BG_models<boost::geometry::cs::cartesian>>::
|
|
multilinestring_touches_geometry(Geometry *g1, Geometry *g2,
|
|
bool *pnull_value);
|
|
template int
|
|
BG_wrap<BG_models<boost::geometry::cs::cartesian>>::polygon_touches_geometry(
|
|
Geometry *g1, Geometry *g2, bool *pnull_value);
|
|
template int BG_wrap<BG_models<boost::geometry::cs::cartesian>>::
|
|
multipolygon_touches_geometry(Geometry *g1, Geometry *g2,
|
|
bool *pnull_value);
|