Search code examples
c++c++11boostboost-geometry

Intersection of boost::geometry::model::linestring with boost::geometry::model::polygon


I am trying to find the portion of a linestring that is inside of a polygon. I tried the intersection function, but it seems to just find the actual points of intersection rather than the portion of the linestring that is overlapping the polygon. Is there any way to get this object?

Here is a demo situation:

#include <iostream>
#include <fstream>

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/io/svg/svg_mapper.hpp>
#include <boost/geometry/geometries/linestring.hpp>

using point_type = boost::geometry::model::d2::point_xy<double>;
using polygon_type = boost::geometry::model::polygon<point_type>;
using linestring_type = boost::geometry::model::linestring<point_type>;

int main()
{
    polygon_type polygon;

    polygon.outer().push_back(point_type{10,10});
    polygon.outer().push_back(point_type{12,10});
    polygon.outer().push_back(point_type{12,12});
    polygon.outer().push_back(point_type{10,12});
    polygon.outer().push_back(point_type{10,10});

    linestring_type linestring;
    linestring.push_back(point_type{11,9});
    linestring.push_back(point_type{11,11});
    linestring.push_back(point_type{13,11});

    // Expected intersections at (11, 10) and (12, 11)

    std::ofstream svg("both.svg");

    linestring_type output;
    boost::geometry::intersection(polygon, linestring, output);

    for(auto iter = output.begin(); iter != output.end(); ++iter) {
        std::cout << boost::geometry::get<0>(*iter) << " " << boost::geometry::get<1>(*iter) << std::endl;
    }
// The output is:
//    11 10
//    12 11

// But I want it to be:
//    11 10
//    11 11
//    12 11
    return 0;
}

Solution

  • It appears that you must use a multi_linestring as the output type:

    #include <iostream>
    
    #include <boost/geometry.hpp>
    #include <boost/geometry/geometries/point_xy.hpp>
    #include <boost/geometry/geometries/polygon.hpp>
    #include <boost/geometry/geometries/linestring.hpp>
    #include <boost/geometry/multi/geometries/multi_linestring.hpp>
    
    using point_type = boost::geometry::model::d2::point_xy<double>;
    using polygon_type = boost::geometry::model::polygon<point_type>;
    using linestring_type = boost::geometry::model::linestring<point_type>;
    using multi_linestring_type = boost::geometry::model::multi_linestring<linestring_type>;
    
    int main()
    {
        polygon_type polygon;
    
        polygon.outer().push_back(point_type{10,10});
        polygon.outer().push_back(point_type{10,12});
        polygon.outer().push_back(point_type{12,12});
        polygon.outer().push_back(point_type{12,10});
        polygon.outer().push_back(point_type{10,10});
    
        linestring_type linestring;
        linestring.push_back(point_type{11,9});
        linestring.push_back(point_type{11,11});
        linestring.push_back(point_type{13,11});
    
        // Expected intersections at (11, 10) and (12, 11)
    
        multi_linestring_type intersection;
        boost::geometry::intersection(polygon, linestring, intersection);
    
        for(auto intersectionIter = intersection.begin(); intersectionIter != intersection.end(); ++intersectionIter) {
            linestring_type intersectionPiece = *intersectionIter;
            std::cout << "Piece:" << std::endl;
            for(auto intersectionPieceIter = intersectionPiece.begin(); intersectionPieceIter != intersectionPiece.end(); ++intersectionPieceIter) {
                std::cout << boost::geometry::get<0>(*intersectionPieceIter) << " " << boost::geometry::get<1>(*intersectionPieceIter) << std::endl;
            }
    
        }
    
        return 0;
    }