在多边形内查找 Boost rtree 元素
Find Boost rtree elements inside a polygon
我想使用 Boost C++ 库找到在 rtree 中索引的所有元素,这些元素与带孔的多边形的外环相交但不完全在任何孔内。
我知道如何获得与外环相交的元素:
// Constructing the exterior ring polygon
Boost2dRing p;
for (int i = 0; i < numPunts; i++)
{
x = Punts.at(i).x;
y = Punts.at(i).y;
p.push_back(Boost2dPoint(x, y));
}
// Getting the intersecting elements with that polygon
m_RTree.query(bgi::intersects(p), std::back_inserter(res));
...
// Constructing the polygon for the inner ring (hole)
Boost2dRing p;
for (int i = 0; i < numPuntsHole; i++)
{
x = PuntsHole.at(i).x;
y = PuntsHole.at(i).y;
pHole.push_back(Boost2dPoint(x, y));
}
// Now I try to get the elements inside completely this polygon but I get a compilation error
m_RTree.query(bgi::within(pHole), std::back_inserter(res));
错误信息:
error C2664: 'int
boost::mpl::assertion_failed(boost::mpl::assert::type)':
cannot convert argument 1 from 'boost::mpl::failed
************(__cdecl boost::geometry::strategy::within::services::default_strategy::NOT_IMPLEMENTED_FOR_THESE_TYPES::*
***********)(boost::mpl::assert_::types)'
to 'boost::mpl::assert::type' 1> with 1> [ 1>
Geometry1=Boost2dBox, 1> Geometry2=Boost2dRing, 1>
GeometryContained=Boost2dBox, 1>
GeometryContaining=Boost2dRing 1> ] note: No constructor
could take the source type, or constructor overload resolution was
ambiguous
有什么实现这个目标的提示吗?
within 谓词未针对您选择的几何操作数实现。
但是,您可以用 很多 更少的工作量来做您想做的事。假设您有戒指,例如:
Boost2dRing exterior, interior;
bg::read_wkt("POLYGON((0.1 0.1,0.1 0.5,0.5 0.5,0.5 0.1,0.1 0.1))", exterior);
bg::read_wkt("POLYGON((0.2 0.2,0.2 0.4,0.4 0.4,0.4 0.2,0.2 0.2))", interior);
现在,Boost Geometry 有一个 Polygon 的概念,它是一个外环和(多个)内环:
A polygon is A polygon is a planar surface defined by one exterior boundary and zero or more interior boundaries (OGC Simple Feature Specification)
所以,让我们改用它:
bg::reverse(interior);
Boost2dPolygon polygon;
polygon.outer() = exterior;
polygon.inners().push_back(interior);
Note that the orientation of the inner ring is inverted.
或者,实际上,直接使用构造函数:
Boost2dPolygon polygon({exterior, interior});
或者,甚至立即从 WKT 读取它:
bg::read_wkt("POLYGON((0.1 0.1,0.1 0.5,0.5 0.5,0.5 0.1,0.1 0.1) (0.2 0.2,0.4 0.2,0.4 0.4,0.2 0.4,0.2 0.2))", polygon);
现在一次查询即可:
std::vector<RTree::value_type> res;
m_RTree.query(bgi::intersects(polygon), std::back_inserter(res));
完整演示!
给定以下 sample()
树内容:
using RTree = bgi::rtree<std::pair<Boost2dBox, std::string>, bgi::rstar<16> >;
RTree sample() {
RTree tree;
std::pair<std::string, std::string> items[] = {
{ "BOX(0.2 0.2,0.2 0.4,0.4 0.4,0.4 0.2,0.2 0.2)", "ok" },
{ "BOX(0.28 0.28,0.28 0.32,0.32 0.32,0.32 0.28,0.28 0.28)", "within gap" },
{ "BOX(0.28 0.28,0.28 0.32,0.36 0.32,0.36 0.28,0.28 0.28)", "small overlap" },
{ "BOX(2 2,2 4,4 4,4 2,2 2)", "outside exterior" },
};
for (auto& item : items) {
Boost2dBox box;
bg::read_wkt(item.first, box);
checks("box", box);
tree.insert({box, item.second});
}
return tree;
}
我们可以手动测试:
RTree const m_RTree = sample();
std::cout << "Sample tree:\n";
for (auto& value : m_RTree) {
std::cout << " - " << std::quoted(value.second) << ": " << bg::wkt(value.first) << "\n";
Boost2dMultiPolygon mp;
if (bg::intersection(polygon, value.first, mp))
std::cout << " (intersection is " << bg::wkt(mp) << ")\n";
}
打印
Sample tree:
- "ok": POLYGON((0.2 0.2,0.2 0.4,0.4 0.4,0.4 0.2,0.2 0.2))
(intersection is MULTIPOLYGON(((0.2 0.2,0.2 0.4,0.4 0.4,0.4 0.2,0.2 0.2),(0.25 0.25,0.35 0.25,0.35 0.35,0.25 0.35,0.25 0.25))))
- "within gap": POLYGON((0.28 0.28,0.28 0.32,0.32 0.32,0.32 0.28,0.28 0.28))
(intersection is MULTIPOLYGON())
- "small overlap": POLYGON((0.28 0.28,0.28 0.32,0.36 0.32,0.36 0.28,0.28 0.28))
(intersection is MULTIPOLYGON(((0.35 0.32,0.36 0.32,0.36 0.28,0.35 0.28,0.35 0.32))))
- "outside exterior": POLYGON((2 2,2 4,4 4,4 2,2 2))
(intersection is MULTIPOLYGON())
并验证与树查询比较的结果:
m_RTree.query(bgi::intersects(polygon), std::back_inserter(matches));
std::cout << "Intersecting with: ";
for (auto& match : matches) std::cout << " " << std::quoted(match.second) << " ";
打印:
Intersecting with: "ok" "small overlap"
全部查看Live On Coliru
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/multi_polygon.hpp>
#include <boost/geometry/geometries/linestring.hpp>
#include <boost/geometry/geometries/multi_polygon.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/arithmetic/arithmetic.hpp>
#include <boost/geometry/algorithms/within.hpp>
#include <boost/geometry/algorithms/intersects.hpp>
#include <boost/geometry/algorithms/envelope.hpp>
#include <boost/geometry/algorithms/intersection.hpp>
#include <boost/geometry/index/rtree.hpp>
#include <boost/geometry/index/predicates.hpp>
#include <boost/geometry/index/adaptors/query.hpp>
#include <boost/geometry/io/io.hpp>
#include <iostream>
#include <fstream>
namespace bg = boost::geometry;
namespace bgi = boost::geometry::index;
using Boost2dPoint = bg::model::d2::point_xy<double>;
using Boost2dRing = bg::model::ring<Boost2dPoint>;
using Boost2dPolygon = bg::model::polygon<Boost2dPoint>;
using Boost2dMultiPolygon = bg::model::multi_polygon<Boost2dPolygon>;
using Boost2dBox = bg::model::box<Boost2dPoint>;
template <typename G> void checks(std::string name, G& geom) {
std::cout << name << ": " << bg::wkt(geom) << "\n";
std::string reason;
if (!bg::is_valid(geom, reason)) {
std::cout << name << ": " << reason << "\n";
bg::correct(geom);
std::cout << bg::wkt(geom) << "\n";
if (!bg::is_valid(geom, reason)) {
std::cout << name << " corrected: " << reason << "\n";
}
}
}
using RTree = bgi::rtree<std::pair<Boost2dBox, std::string>, bgi::rstar<16> >;
RTree sample() {
RTree tree;
std::pair<std::string, std::string> items[] = {
{ "BOX(0.2 0.2,0.2 0.4,0.4 0.4,0.4 0.2,0.2 0.2)", "ok" },
{ "BOX(0.28 0.28,0.28 0.32,0.32 0.32,0.32 0.28,0.28 0.28)", "within gap" },
{ "BOX(0.28 0.28,0.28 0.32,0.36 0.32,0.36 0.28,0.28 0.28)", "small overlap" },
{ "BOX(2 2,2 4,4 4,4 2,2 2)", "outside exterior" },
};
for (auto& item : items) {
Boost2dBox box;
bg::read_wkt(item.first, box);
checks("box", box);
tree.insert({box, item.second});
}
return tree;
}
int main() {
Boost2dPolygon polygon;
bg::read_wkt("POLYGON((0.1 0.1,0.1 0.5,0.5 0.5,0.5 0.1,0.1 0.1) (0.25 0.25,0.35 0.25,0.35 0.35,0.25 0.35,0.25 0.25))", polygon);
checks("polygon", polygon);
RTree const m_RTree = sample();
std::cout << "Sample tree:\n";
for (auto& value : m_RTree) {
std::cout << " - " << std::quoted(value.second) << ": " << bg::wkt(value.first) << "\n";
Boost2dMultiPolygon mp;
if (bg::intersection(polygon, value.first, mp))
std::cout << " (intersection is " << bg::wkt(mp) << ")\n";
}
std::cout << "\n";
std::vector<RTree::value_type> matches;
m_RTree.query(bgi::intersects(polygon), std::back_inserter(matches));
std::cout << "Intersecting with: ";
for (auto& match : matches) std::cout << " " << std::quoted(match.second) << " ";
std::cout << "\n";
}
我想使用 Boost C++ 库找到在 rtree 中索引的所有元素,这些元素与带孔的多边形的外环相交但不完全在任何孔内。
我知道如何获得与外环相交的元素:
// Constructing the exterior ring polygon
Boost2dRing p;
for (int i = 0; i < numPunts; i++)
{
x = Punts.at(i).x;
y = Punts.at(i).y;
p.push_back(Boost2dPoint(x, y));
}
// Getting the intersecting elements with that polygon
m_RTree.query(bgi::intersects(p), std::back_inserter(res));
...
// Constructing the polygon for the inner ring (hole)
Boost2dRing p;
for (int i = 0; i < numPuntsHole; i++)
{
x = PuntsHole.at(i).x;
y = PuntsHole.at(i).y;
pHole.push_back(Boost2dPoint(x, y));
}
// Now I try to get the elements inside completely this polygon but I get a compilation error
m_RTree.query(bgi::within(pHole), std::back_inserter(res));
错误信息:
error C2664: 'int boost::mpl::assertion_failed(boost::mpl::assert::type)': cannot convert argument 1 from 'boost::mpl::failed ************(__cdecl boost::geometry::strategy::within::services::default_strategy::NOT_IMPLEMENTED_FOR_THESE_TYPES::* ***********)(boost::mpl::assert_::types)' to 'boost::mpl::assert::type' 1> with 1> [ 1> Geometry1=Boost2dBox, 1> Geometry2=Boost2dRing, 1>
GeometryContained=Boost2dBox, 1>
GeometryContaining=Boost2dRing 1> ] note: No constructor could take the source type, or constructor overload resolution was ambiguous
有什么实现这个目标的提示吗?
within 谓词未针对您选择的几何操作数实现。
但是,您可以用 很多 更少的工作量来做您想做的事。假设您有戒指,例如:
Boost2dRing exterior, interior;
bg::read_wkt("POLYGON((0.1 0.1,0.1 0.5,0.5 0.5,0.5 0.1,0.1 0.1))", exterior);
bg::read_wkt("POLYGON((0.2 0.2,0.2 0.4,0.4 0.4,0.4 0.2,0.2 0.2))", interior);
现在,Boost Geometry 有一个 Polygon 的概念,它是一个外环和(多个)内环:
A polygon is A polygon is a planar surface defined by one exterior boundary and zero or more interior boundaries (OGC Simple Feature Specification)
所以,让我们改用它:
bg::reverse(interior);
Boost2dPolygon polygon;
polygon.outer() = exterior;
polygon.inners().push_back(interior);
Note that the orientation of the inner ring is inverted.
或者,实际上,直接使用构造函数:
Boost2dPolygon polygon({exterior, interior});
或者,甚至立即从 WKT 读取它:
bg::read_wkt("POLYGON((0.1 0.1,0.1 0.5,0.5 0.5,0.5 0.1,0.1 0.1) (0.2 0.2,0.4 0.2,0.4 0.4,0.2 0.4,0.2 0.2))", polygon);
现在一次查询即可:
std::vector<RTree::value_type> res;
m_RTree.query(bgi::intersects(polygon), std::back_inserter(res));
完整演示!
给定以下 sample()
树内容:
using RTree = bgi::rtree<std::pair<Boost2dBox, std::string>, bgi::rstar<16> >;
RTree sample() {
RTree tree;
std::pair<std::string, std::string> items[] = {
{ "BOX(0.2 0.2,0.2 0.4,0.4 0.4,0.4 0.2,0.2 0.2)", "ok" },
{ "BOX(0.28 0.28,0.28 0.32,0.32 0.32,0.32 0.28,0.28 0.28)", "within gap" },
{ "BOX(0.28 0.28,0.28 0.32,0.36 0.32,0.36 0.28,0.28 0.28)", "small overlap" },
{ "BOX(2 2,2 4,4 4,4 2,2 2)", "outside exterior" },
};
for (auto& item : items) {
Boost2dBox box;
bg::read_wkt(item.first, box);
checks("box", box);
tree.insert({box, item.second});
}
return tree;
}
我们可以手动测试:
RTree const m_RTree = sample();
std::cout << "Sample tree:\n";
for (auto& value : m_RTree) {
std::cout << " - " << std::quoted(value.second) << ": " << bg::wkt(value.first) << "\n";
Boost2dMultiPolygon mp;
if (bg::intersection(polygon, value.first, mp))
std::cout << " (intersection is " << bg::wkt(mp) << ")\n";
}
打印
Sample tree:
- "ok": POLYGON((0.2 0.2,0.2 0.4,0.4 0.4,0.4 0.2,0.2 0.2))
(intersection is MULTIPOLYGON(((0.2 0.2,0.2 0.4,0.4 0.4,0.4 0.2,0.2 0.2),(0.25 0.25,0.35 0.25,0.35 0.35,0.25 0.35,0.25 0.25))))
- "within gap": POLYGON((0.28 0.28,0.28 0.32,0.32 0.32,0.32 0.28,0.28 0.28))
(intersection is MULTIPOLYGON())
- "small overlap": POLYGON((0.28 0.28,0.28 0.32,0.36 0.32,0.36 0.28,0.28 0.28))
(intersection is MULTIPOLYGON(((0.35 0.32,0.36 0.32,0.36 0.28,0.35 0.28,0.35 0.32))))
- "outside exterior": POLYGON((2 2,2 4,4 4,4 2,2 2))
(intersection is MULTIPOLYGON())
并验证与树查询比较的结果:
m_RTree.query(bgi::intersects(polygon), std::back_inserter(matches));
std::cout << "Intersecting with: ";
for (auto& match : matches) std::cout << " " << std::quoted(match.second) << " ";
打印:
Intersecting with: "ok" "small overlap"
全部查看Live On Coliru
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/multi_polygon.hpp>
#include <boost/geometry/geometries/linestring.hpp>
#include <boost/geometry/geometries/multi_polygon.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/arithmetic/arithmetic.hpp>
#include <boost/geometry/algorithms/within.hpp>
#include <boost/geometry/algorithms/intersects.hpp>
#include <boost/geometry/algorithms/envelope.hpp>
#include <boost/geometry/algorithms/intersection.hpp>
#include <boost/geometry/index/rtree.hpp>
#include <boost/geometry/index/predicates.hpp>
#include <boost/geometry/index/adaptors/query.hpp>
#include <boost/geometry/io/io.hpp>
#include <iostream>
#include <fstream>
namespace bg = boost::geometry;
namespace bgi = boost::geometry::index;
using Boost2dPoint = bg::model::d2::point_xy<double>;
using Boost2dRing = bg::model::ring<Boost2dPoint>;
using Boost2dPolygon = bg::model::polygon<Boost2dPoint>;
using Boost2dMultiPolygon = bg::model::multi_polygon<Boost2dPolygon>;
using Boost2dBox = bg::model::box<Boost2dPoint>;
template <typename G> void checks(std::string name, G& geom) {
std::cout << name << ": " << bg::wkt(geom) << "\n";
std::string reason;
if (!bg::is_valid(geom, reason)) {
std::cout << name << ": " << reason << "\n";
bg::correct(geom);
std::cout << bg::wkt(geom) << "\n";
if (!bg::is_valid(geom, reason)) {
std::cout << name << " corrected: " << reason << "\n";
}
}
}
using RTree = bgi::rtree<std::pair<Boost2dBox, std::string>, bgi::rstar<16> >;
RTree sample() {
RTree tree;
std::pair<std::string, std::string> items[] = {
{ "BOX(0.2 0.2,0.2 0.4,0.4 0.4,0.4 0.2,0.2 0.2)", "ok" },
{ "BOX(0.28 0.28,0.28 0.32,0.32 0.32,0.32 0.28,0.28 0.28)", "within gap" },
{ "BOX(0.28 0.28,0.28 0.32,0.36 0.32,0.36 0.28,0.28 0.28)", "small overlap" },
{ "BOX(2 2,2 4,4 4,4 2,2 2)", "outside exterior" },
};
for (auto& item : items) {
Boost2dBox box;
bg::read_wkt(item.first, box);
checks("box", box);
tree.insert({box, item.second});
}
return tree;
}
int main() {
Boost2dPolygon polygon;
bg::read_wkt("POLYGON((0.1 0.1,0.1 0.5,0.5 0.5,0.5 0.1,0.1 0.1) (0.25 0.25,0.35 0.25,0.35 0.35,0.25 0.35,0.25 0.25))", polygon);
checks("polygon", polygon);
RTree const m_RTree = sample();
std::cout << "Sample tree:\n";
for (auto& value : m_RTree) {
std::cout << " - " << std::quoted(value.second) << ": " << bg::wkt(value.first) << "\n";
Boost2dMultiPolygon mp;
if (bg::intersection(polygon, value.first, mp))
std::cout << " (intersection is " << bg::wkt(mp) << ")\n";
}
std::cout << "\n";
std::vector<RTree::value_type> matches;
m_RTree.query(bgi::intersects(polygon), std::back_inserter(matches));
std::cout << "Intersecting with: ";
for (auto& match : matches) std::cout << " " << std::quoted(match.second) << " ";
std::cout << "\n";
}