Boost logo

Geometry :

Subject: [ggl] box_range is not a valid range
From: zzsj (feverzsj)
Date: 2011-05-12 09:39:20


hi, Barend

> Besides this I also fixed/implemented the point_order on a box_view, if
> you specify Reverse it is counter clockwise, as expected. Closure might
> complete it (but requires another copy-policy and an adapted approach).

In the old solution, Closure could be simply achieved by setting the end index. For example:

template<typename Box, bool ClockWise = true, bool Closed = true>
class box2d_range
{
    ...

    const_iterator begin() const { return const_iterator(m_points, 0); }
    const_iterator end() const { return const_iterator(m_points, 4 + Closed); }

    void init(Box const& box)
    {
        ggl::detail::assign_box_corners_oriented<!ClockWise>(box, m_points);
    }

private :
    point_type m_points[4];
}

This could be also possible for points_view.

>> Also, now that box_view is of ring type, why it cannot be an opened ring?
>> The view concept is a kinda confusing concept. It mixes the range and geometry concepts.
>> I think the view concept should follow the range concept.
>> As mentioned in "[ggl] transform linestring into a ring", I found two geometry wrappers very useful in many aspects. Here they are:
>
> OK, we will think / discuss about this.

Thanks. I've attached my ggl helpers. It includes the two wrappers(support box with box2d_range), and some useful functions.

regards, ZhouShuangJiang
-------------- next part --------------
#ifndef _GGL_HELPER_H_2011_4_15_15_34_12
#define _GGL_HELPER_H_2011_4_15_15_34_12

#include <boost/range.hpp>

#include <boost/geometry/geometry.hpp>
#include <boost/geometry/geometries/geometries.hpp>
#include <boost/geometry/multi/multi.hpp>
#include <boost/geometry/views/box_view.hpp>
#include <boost/geometry/geometries/register/point.hpp>

namespace ggl = boost::geometry;

// test if a ring is oriented correctly with resepect
// to the presumed orientation
template<class Ring>
inline bool valid_orientation(Ring const& r)
{
    return boost::geometry::area(r) > 0;
}

// test if a ring's actaul closure is same as its presumed closure;
template<class Ring>
inline bool valid_closure(Ring const& r)
{
    if(boost::size(r) < 3)
        return false; // ?

    if(ggl::disjoint(*boost::begin(r), *(boost::end(r) - 1)))
        return ggl::closure<Ring>::value == ggl::open;
    return ggl::closure<Ring>::value == ggl::closed;
}

template<typename Box, bool ClockWise = true, bool Closed = true>
class box2d_range
{
public :
    typedef typename ggl::point_type<Box>::type point_type;

    struct box2d_iterator
        : public boost::iterator_facade<
            box2d_iterator,
            point_type const, // read only
            boost::random_access_traversal_tag
>
    {
        box2d_iterator(point_type const* p = 0, int i = 0)
            : m_points(p), m_index(i) {}

        typedef std::ptrdiff_t difference_type;

    private:
        friend class boost::iterator_core_access;

        point_type const& dereference() const
        {
            assert(m_points);

            if (m_index >= 0 && m_index <= 3)
            {
                return m_points[m_index];
            }
            // If it index is 4, or other, return first point
            return m_points[0];
        }

        bool equal(box2d_iterator const& other) const
        {
            return other.m_index == m_index;
        }

        void increment()
        {
            m_index++;
        }

        void decrement()
        {
            m_index--;
        }

        void advance(difference_type n)
        {
            m_index += n;
        }

        difference_type distance_to(box2d_iterator const& other) const
        {
            return other.m_index - m_index;
        }

        int m_index;
        point_type const* m_points;
    };

    typedef box2d_iterator const_iterator;
    typedef box2d_iterator iterator; // must be defined

    explicit box2d_range(Box const& box)
    {
        init(box);
    }

    const_iterator begin() const { return const_iterator(m_points, 0); }
    const_iterator end() const { return const_iterator(m_points, 4 + Closed); }

    // It may not be used non-const, so comment this:
    //iterator begin() { return m_begin; }
    //iterator end() { return m_end; }

    void init(Box const& box)
    {
        ggl::detail::assign_box_corners_oriented<!ClockWise>(box, m_points);
    }

private :
    point_type m_points[4];
};

namespace detail{

template<class tag, class X, bool CloseOpenedRing, bool ClosedBox, bool ClockwiseBox>
struct linestring_wrapper_dispatch // default for range
{
    typedef ggl::identity_view<X> base_type;
};

template<class X, bool CloseOpenedRing, bool ClosedBox, bool ClockwiseBox>
struct linestring_wrapper_dispatch<ggl::ring_tag, X, CloseOpenedRing, ClosedBox, ClockwiseBox>
{
    typedef typename boost::mpl::if_c<CloseOpenedRing,
        typename ggl::closeable_view<X, ggl::closure<X>::value>::type,
        ggl::identity_view<X>
>::type base_type;
};

template<class X, bool CloseOpenedRing, bool ClosedBox, bool ClockwiseBox>
struct linestring_wrapper_dispatch<ggl::box_tag, X, CloseOpenedRing, ClosedBox, ClockwiseBox>
{
    typedef box2d_range<X, ClosedBox, ClockwiseBox> base_type;
};

template<class tag, class X, bool ClockWise, bool Closed>
struct ring_wrapper_dispatch // default for range/linestring
{
    typedef ggl::identity_view<X> base_type;
};

template<class X, bool ClockWise, bool Closed>
struct ring_wrapper_dispatch<ggl::box_tag, X, ClockWise, Closed>
{
    typedef box2d_range<X, ClockWise, Closed> base_type;
};

} // namespace detail

// warp X as linestring
// X : ring, box, range/other geometry(since other geometry type could be already a range type)
// CloseOpenedRing : close presumed open ring if set to true, otherwise do nothing, ignored if X is box
// note: box is added for convenience, user can also use box2d_range to transform box into wanted range.
template<class X, bool CloseOpenedRing = true,
         bool ClosedBox = true, bool ClockwiseBox = true>
struct linestring_wrapper
    : public detail::linestring_wrapper_dispatch<
        typename ggl::tag<X>::type, X, CloseOpenedRing, ClosedBox, ClockwiseBox>::base_type
{
    typedef typename detail::linestring_wrapper_dispatch<
        typename ggl::tag<X>::type, X, CloseOpenedRing, ClosedBox, ClockwiseBox>::base_type base_type;

    explicit linestring_wrapper(X& x) : base_type(x) {}
};

// for defalut
template<class X>
inline linestring_wrapper<X> as_linestring(X& x)
{
    return linestring_wrapper<X>(x);
}

template<class X>
inline linestring_wrapper<X const> as_linestring(X const& x)
{
    return linestring_wrapper<X const>(x);
}

// for ring
template<bool CloseOpenedRing, class Ring>
inline linestring_wrapper<Ring, CloseOpenedRing> as_linestring(Ring& r)
{
    return linestring_wrapper<Ring, CloseOpenedRing>(r);
}

template<bool CloseOpenedRing, class Ring>
inline linestring_wrapper<Ring const, CloseOpenedRing> as_linestring(Ring const& r)
{
    return linestring_wrapper<Ring const, CloseOpenedRing>(r);
}

// for box
template<bool ClosedBox, bool ClockwiseBox, class Box>
inline linestring_wrapper<Box, false, ClosedBox, ClockwiseBox> as_linestring(Box& b)
{
    return linestring_wrapper<Box, false, ClosedBox, ClockwiseBox>(b);
}

template<bool ClosedBox, bool ClockwiseBox, class Box>
inline linestring_wrapper<Box const, false, ClosedBox, ClockwiseBox> as_linestring(Box const& b)
{
    return linestring_wrapper<Box const, false, ClosedBox, ClockwiseBox>(b);
}

// warp X as ring
// X : linestring, box, range/other geometry(since other geometry type could be already a range type)
template<class X, bool ClockWise = true, bool Closed = false> // note: presumed open on default
struct ring_wrapper
    : public detail::ring_wrapper_dispatch<
        typename ggl::tag<X>::type, X, ClockWise, Closed>::base_type
{
    typedef typename detail::ring_wrapper_dispatch<
        typename ggl::tag<X>::type, X, ClockWise, Closed>::base_type base_type;

    ring_wrapper(X& x) : base_type(x) {}
};

template<class X>
inline ring_wrapper<X> as_ring(X& x)
{
    return ring_wrapper<X>(x);
}

template<class X>
inline ring_wrapper<X const> as_ring(X const& x)
{
    return ring_wrapper<X const>(x);
}

template<bool ClockWise, bool Closed, class X>
inline ring_wrapper<X, ClockWise, Closed> as_ring(X& x)
{
    return ring_wrapper<X, ClockWise, Closed>(x);
}

template<bool ClockWise, bool Closed, class X>
inline ring_wrapper<X const, ClockWise, Closed> as_ring(X const& x)
{
    return ring_wrapper<X const, ClockWise, Closed>(x);
}

namespace boost{ namespace geometry{ namespace traits{

// for linestring_wrapper
template<class X, bool CloseOpenedRing, bool ClosedBox, bool ClockwiseBox>
struct tag<linestring_wrapper<X, CloseOpenedRing, ClosedBox, ClockwiseBox> >
{
    typedef linestring_tag type;
};

// for ring_wrapper
template<class X, bool ClockWise, bool Closed>
struct tag<ring_wrapper<X, ClockWise, Closed> >
{
    typedef ring_tag type;
};

template<class X, bool Closed>
struct point_order<ring_wrapper<X, false, Closed> >
{
    static const order_selector value = counterclockwise;
};

template<class X, bool Closed>
struct point_order<ring_wrapper<X, true, Closed> >
{
    static const order_selector value = clockwise;
};

template<class X, bool PointOrder>
struct closure<ring_wrapper<X, PointOrder, true> >
{
    static const closure_selector value = closed;
};

template<class X, bool PointOrder>
struct closure<ring_wrapper<X, PointOrder, false> >
{
    static const closure_selector value = open;
};

} } } // namespace boost::geometry::traits

#endif /* _GGL_HELPER_H_2011_4_15_15_34_12 */


Geometry list run by mateusz at loskot.net