如何计算点 o filled/unfilled 矩形的距离
How to calculate distance from point o filled/unfilled rectangle
我正在使用 Qt 5 可视化不同种类的几何图形。
我有一个 QRect
可视化为已填充或未填充。
现在我想使用 boost::geometry
计算 QPoint
到该矩形的距离。
矩形内的点在填充时应有 0
的距离,在未填充时应与下一行的距离。
由于 Box
的文档没有提到它是一种形状,我认为我可以将它用于这种情况,并将 Box
概念改编为 QRect
.
但以下示例不起作用,因为 Box
被视为形状,因此总是 "filled"。
#include <iostream>
#include <boost/geometry.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/geometries/register/point.hpp>
#include <QtCore/QPoint>
#include <QtCore/QRect>
BOOST_GEOMETRY_REGISTER_POINT_2D_GET_SET(QPoint, int, boost::geometry::cs::cartesian, x, y, setX, setY);
namespace boost { namespace geometry {
namespace traits
{
template <> struct tag<QRect> { typedef box_tag type; };
template <> struct point_type<QRect> { typedef QPoint type; };
template <std::size_t Index, std::size_t Dimension>
struct indexed_access<QRect, Index, Dimension>
{
typedef typename geometry::coordinate_type<QRect>::type coordinate_type;
static inline coordinate_type get(const QRect &r)
{
if (Index == boost::geometry::min_corner)
return geometry::get<Dimension>(r.topLeft());
else
return geometry::get<Dimension>(r.bottomRight());
}
};
}
}}
double distance(const QPoint &p, const QRect &r, const bool filled)
{
if (filled && r.contains(p))
return 0.0;
else
return boost::geometry::distance(p, r);
}
int main()
{
QRect r(QPoint(0, 0), QPoint(20, 10));
QPoint p(5, 5); // whithin rect
// 0, instead of 5
std::cout << "not filled: " << distance(p, r, false) << '\n';
// 0, as expected
std::cout << "filled: " << distance(p, r, true) << '\n';
}
运行 g++ -Wall -O2 -fPIC main.cpp -I/usr/include/qt -lQtCore
在 Linux.
上构建
我当然可以将 LineString
用于未填充的情况,尽管那样会有动态分配。
除非我创建一个使用底层 QRect
的手动改编,否则这将是一项相当大的工作。
如何最好地解决这个问题?
的确,您是对的,因为 Box 表示填充形状,所以需要 line-string。实际上,在我的快速测试中,多边形也是如此。
You could of course create a fake "holey" polygon that has an edge of some small width. But that's cheating and certainly less efficient
的确,你可以在这里使用线串:
#include <iostream>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/linestring.hpp>
using namespace boost::geometry;
int main()
{
using Point = model::d2::point_xy<double>;
using Rect = model::linestring<Point>;
Rect rect;
rect.insert(rect.end(), {
Point { 0, 0 },
Point { 10, 0 },
Point { 10, 20 },
Point { 0, 20 },
Point { 0, 0 },
});
std::cout << "distance point within: " << distance(rect, Point(5, 5)) << '\n'; // 0
std::cout << "distance point not within: " << distance(rect, Point(15, 5)) << '\n'; // 5
}
打印
distance point within: 5
distance point not within: 5
我看不出有任何理由相信线串比多边形效率低(它基本上与多边形的外环相同)。
不过,确实盒测可能会更快。我建议你分析一下。如果速度更快,只需使用盒子,以防形状已知为 "filled",否则使用线串。
支持非填充 QRect
的一种相对简单的方法是使用 LineString
概念。
为了避免分配的开销,可以使用 std::array
。
在初始代码的基础上,需要添加以下部分:
#include <array>
using RectLineString = std::array<QPoint, 5>;
BOOST_GEOMETRY_REGISTER_LINESTRING(RectLineString)
double distance(const QPoint &p, const QRect &r, const bool filled)
{
if (filled && r.contains(p))
return 0.0;
else
{
RectLineString rls;
fillRectLineString(rls, rect);
return boost::geometry::distance(p, rls);
}
}
fillrectLineString
应该是什么样子取决于您希望如何处理 QRect::bottomRight()
returns QPoint(rect.x() + rect.width() - 1, rect.y() + rect.height() - 1)
的问题。
所以我在这里提供两个版本:
// bottomRight() is QPoint(rect.x() + rect.width() - 1, rect.y() + rect.height() - 1)
void fillRectLineString1(RectLineString &rls, const QRect &rect)
{
rls[0] = rect.topLeft();
rls[1] = rect.topRight();
rls[2] = rect.bottomRight();
rls[3] = rect.bottomLeft();
rls[4] = rect.topLeft();
}
// bottomRight() is QPoint(rect.x() + rect.width(), rect.y() + rect.height())
void fillRectLineString2(RectLineString &rls, const QRect &rect)
{
rls[0] = QPoint(rect.x(), rect.y());
rls[1] = QPoint(rect.x() + rect.width(), rect.y());
rls[2] = QPoint(rect.x() + rect.width(), rect.y() + rect.height());
rls[3] = QPoint(rect.x(), rect.y() + rect.height());
rls[4] = QPoint(rect.x(), rect.y());
}
我正在使用 Qt 5 可视化不同种类的几何图形。
我有一个 QRect
可视化为已填充或未填充。
现在我想使用 boost::geometry
计算 QPoint
到该矩形的距离。
矩形内的点在填充时应有 0
的距离,在未填充时应与下一行的距离。
由于 Box
的文档没有提到它是一种形状,我认为我可以将它用于这种情况,并将 Box
概念改编为 QRect
.
但以下示例不起作用,因为 Box
被视为形状,因此总是 "filled"。
#include <iostream>
#include <boost/geometry.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/geometries/register/point.hpp>
#include <QtCore/QPoint>
#include <QtCore/QRect>
BOOST_GEOMETRY_REGISTER_POINT_2D_GET_SET(QPoint, int, boost::geometry::cs::cartesian, x, y, setX, setY);
namespace boost { namespace geometry {
namespace traits
{
template <> struct tag<QRect> { typedef box_tag type; };
template <> struct point_type<QRect> { typedef QPoint type; };
template <std::size_t Index, std::size_t Dimension>
struct indexed_access<QRect, Index, Dimension>
{
typedef typename geometry::coordinate_type<QRect>::type coordinate_type;
static inline coordinate_type get(const QRect &r)
{
if (Index == boost::geometry::min_corner)
return geometry::get<Dimension>(r.topLeft());
else
return geometry::get<Dimension>(r.bottomRight());
}
};
}
}}
double distance(const QPoint &p, const QRect &r, const bool filled)
{
if (filled && r.contains(p))
return 0.0;
else
return boost::geometry::distance(p, r);
}
int main()
{
QRect r(QPoint(0, 0), QPoint(20, 10));
QPoint p(5, 5); // whithin rect
// 0, instead of 5
std::cout << "not filled: " << distance(p, r, false) << '\n';
// 0, as expected
std::cout << "filled: " << distance(p, r, true) << '\n';
}
运行 g++ -Wall -O2 -fPIC main.cpp -I/usr/include/qt -lQtCore
在 Linux.
我当然可以将 LineString
用于未填充的情况,尽管那样会有动态分配。
除非我创建一个使用底层 QRect
的手动改编,否则这将是一项相当大的工作。
如何最好地解决这个问题?
的确,您是对的,因为 Box 表示填充形状,所以需要 line-string。实际上,在我的快速测试中,多边形也是如此。
You could of course create a fake "holey" polygon that has an edge of some small width. But that's cheating and certainly less efficient
的确,你可以在这里使用线串:
#include <iostream>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/linestring.hpp>
using namespace boost::geometry;
int main()
{
using Point = model::d2::point_xy<double>;
using Rect = model::linestring<Point>;
Rect rect;
rect.insert(rect.end(), {
Point { 0, 0 },
Point { 10, 0 },
Point { 10, 20 },
Point { 0, 20 },
Point { 0, 0 },
});
std::cout << "distance point within: " << distance(rect, Point(5, 5)) << '\n'; // 0
std::cout << "distance point not within: " << distance(rect, Point(15, 5)) << '\n'; // 5
}
打印
distance point within: 5
distance point not within: 5
我看不出有任何理由相信线串比多边形效率低(它基本上与多边形的外环相同)。
不过,确实盒测可能会更快。我建议你分析一下。如果速度更快,只需使用盒子,以防形状已知为 "filled",否则使用线串。
支持非填充 QRect
的一种相对简单的方法是使用 LineString
概念。
为了避免分配的开销,可以使用 std::array
。
在初始代码的基础上,需要添加以下部分:
#include <array>
using RectLineString = std::array<QPoint, 5>;
BOOST_GEOMETRY_REGISTER_LINESTRING(RectLineString)
double distance(const QPoint &p, const QRect &r, const bool filled)
{
if (filled && r.contains(p))
return 0.0;
else
{
RectLineString rls;
fillRectLineString(rls, rect);
return boost::geometry::distance(p, rls);
}
}
fillrectLineString
应该是什么样子取决于您希望如何处理 QRect::bottomRight()
returns QPoint(rect.x() + rect.width() - 1, rect.y() + rect.height() - 1)
的问题。
所以我在这里提供两个版本:
// bottomRight() is QPoint(rect.x() + rect.width() - 1, rect.y() + rect.height() - 1)
void fillRectLineString1(RectLineString &rls, const QRect &rect)
{
rls[0] = rect.topLeft();
rls[1] = rect.topRight();
rls[2] = rect.bottomRight();
rls[3] = rect.bottomLeft();
rls[4] = rect.topLeft();
}
// bottomRight() is QPoint(rect.x() + rect.width(), rect.y() + rect.height())
void fillRectLineString2(RectLineString &rls, const QRect &rect)
{
rls[0] = QPoint(rect.x(), rect.y());
rls[1] = QPoint(rect.x() + rect.width(), rect.y());
rls[2] = QPoint(rect.x() + rect.width(), rect.y() + rect.height());
rls[3] = QPoint(rect.x(), rect.y() + rect.height());
rls[4] = QPoint(rect.x(), rect.y());
}