如何计算点o填充/未填充矩形的距离

时间:2015-07-01 08:10:17

标签: c++ qt boost boost-geometry

我使用Qt 5可视化不同种类的几何形状。

我有一个QRect可视化为填充或未填充。 现在我想使用QPoint计算boost::geometry到该矩形的距离。 矩形内的一个点在填充时应该有0,在未填充时应该到下一行的距离。

由于Box的文档没有提到它是一个形状,我认为我可以在这种情况下使用它并将Box概念改编为QRect

以下示例不起作用,因为Box被视为形状,因此始终“填充”。

#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的手动修改,否则这将是相当有用的。

我如何才能最好地解决这个问题?

2 个答案:

答案 0 :(得分:1)

确实你需要右线 - 因为Box意味着填充的形状。实际上,在我的快速测试中,多边形也是如此。

  

你当然可以创造一个假的&#34;多孔的&#34;边缘宽度较小的多边形。但那是作弊,当然效率不高

的确,你可以在这里使用线串:

<强> Live On Coliru

#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

我没有理由相信线串的效率低于多边形(它基本上与多边形的外环相同)。

然而,实际上盒子测试可能会更快。我建议你介绍一下。如果速度更快,只需使用盒子,以防已知形状为“#34;填充&#34;否则就是一个线串。

答案 1 :(得分:1)

支持非填充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()返回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());
}