cinder / Cinder

Cinder is a community-developed, free and open source library for professional-quality creative coding in C++.
http://libcinder.org
Other
5.33k stars 939 forks source link

Add method to iterate edges in PolyLine #1720

Open drewish opened 7 years ago

drewish commented 7 years ago

I find myself continually having to iterate over PolyLines as edges rather than vertexes. I usually end up with some code along the lines of:

typedef std::pair<ci::vec2, ci::vec2> seg2;

// For an input: a,b,c
//   when open: a->b,b->c
//   when closed: a->b,b->c,c->a
// For an input: a,b,c,a
//   when open: a->b,b->c,c->a
//   when closed: a->b,b->c,c->a
template<class OI>
void edgesFrom( const ci::PolyLine2f &polyline, OI out )
{
    if ( polyline.size() < 2 ) return;

    std::transform( polyline.begin(), polyline.end() - 1, polyline.begin() + 1, out,
        []( const ci::vec2 &a, const ci::vec2 &b ) { return seg2( a, b ); } );

    if ( polyline.isClosed() ) {
        auto &points = polyline.getPoints();
        if ( points.front() != points.back() ) {
            out++ = seg2( points.back(), points.front() );
        }
    }
}

Or

template<typename T>
void pointsInPairs( const ci::PolyLineT<T> &outline, std::function<void(const T&, const T&)> process )
{
    if ( outline.size() < 2 ) return;

    const std::vector<T> &points = outline.getPoints();
    for ( auto prev = points.begin(), curr = prev + 1; curr != points.end(); ++curr ) {
        process( *prev, *curr );
        prev = curr;
    }
    if ( outline.isClosed() && points.front() != points.back() ) {
        process( points.back(), points.front() );
    }
}

I think it'd be great if the PolyLine class had a similar method or an EdgeIterator that would let me step through the points in pairs and handle the isClosed check for me.

I'm happy to open a PR and take a swing at this but I'd love input on the best pattern to follow.

paulhoux commented 7 years ago

@simongeilfus has just released a Cinder block which adds support for half-edges. I haven't checked it out myself, but I think it makes sense to use a similar approach here: instead of adding more methods to existing classes, add algorithms that can operate on any set of 2D or 3D vertices. With that being said, just adding methods to PolyLine might be a good first step.

drewish commented 7 years ago

Interesting, I'm using a couple of different CGAL packages which have half edge structures (Arrangement_2, Straight Skeleton, Polygon_2) with different kernels so I end up going between them and the screen using PolyLine2. So having some code to make the transformations out of PolyLine2 less tedious would be handy.