1
votes

I'd like to take the geometric difference of two geometric objects with Boost Geometry. The first geometry is:

enter image description here

I always have line segments making up the geometry. I have the coordinates and the segments:

{{-1., -1.}, {1., -1.}, {1., 1.}, {-1., 1.}, {0.6, -1}, {0.6,1.}};
{Line[{{1, 5}, {5, 2}, {2, 3}, {3, 6}, {6, 4}, {4, 1}}], Line[{{5, 6}}]};

were each index in the lines refers to a coordinates. Either of the geometries can have internal boundaries (and holes).

The second geometry:

enter image description here

And I am expecting to obtain this:

enter image description here

I have started with polygon but I do not understand how I could include the interior boundary of the first geometric object. While one can have interior holes I am missing how to have a 'degenerated' polygon like a line. Also it's not clear to me which of the two polygons then would be the outer polygon. Then I thought about line, but there I can not add the internal segment. Can Boost Geometry be used find geometric Boolean operations for geometries with internal boundaries and it so, how would I do that?

The code for the polygon approach that misses the internal boundary; commented out is the line type approach; again with out the internal boundary in first geometric object.

#include <iostream>                                                             
#include <fstream>                                                              
#include <list>                                                                 

#include <boost/geometry.hpp>                                                   
#include <boost/geometry/geometries/point_xy.hpp>                               
#include <boost/geometry/geometries/polygon.hpp>                                

#include <boost/foreach.hpp>                                                    

int main()                                                                      
{                                                                               
    typedef boost::geometry::model::d2::point_xy<double> point_type;            
    typedef boost::geometry::model::polygon<point_type > polygon;               
    //typedef boost::geometry::model::linestring<point_type > line;             

    polygon p1, p2;                                                             
    //line l1, l2;                                                              

    boost::geometry::read_wkt(                                                  
        "POLYGON((-1 -1, 0.6 -1, 1 -1, 1 1, 0.6 1, -1 1))", p1);                

    boost::geometry::read_wkt(                                                  
        "POLYGON((-0.5 -0.5, 2 -0.5, 2 0.5, -0.5 0.5))", p2);                   

    /*                                                                          
    boost::geometry::read_wkt(                                                  
        "LINESTRING(-1 -1, 0.6 -1, 1 -1, 1 1, 0.6 1, -1 1)", l1);               

    boost::geometry::read_wkt(                                                  
        "LINESTRING(-0.5 -0.5, 2 -0.5, 2 0.5, -0.5 0.5)", l2);                  
    */                                                                          

    std::list<polygon> output;                                                  
    boost::geometry::difference(p2, p1, output);                                

    //std::list<line> loutput;                                                  
    //boost::geometry::difference(l2, l1, loutput);                             

    std::ofstream svg("my_map.svg");                                            
    boost::geometry::svg_mapper<point_type> mapper(svg, 400, 400);              

    int i = 0;                                                                  
    BOOST_FOREACH(polygon const& p, output)                                     
    {                                                                           
        mapper.add(p);                                                          
        mapper.map(p, "fill-opacity:0.3;fill:rgb(51,151,53);stroke:rgb(51,151,53);stroke-width:2");  
    }                                                                           

    /*                                                                          
    int i = 0;                                                                  
    BOOST_FOREACH(line const& l, loutput)                                       
    {                                                                           
        mapper.add(l);                                                          
        mapper.map(l, "opacity:0.4;fill:none;stroke:rgb(212,0,0);stroke-width:5");
    }                                                                           
    */                                                                          

    return 0;                                                                   
}
1
You could try to split the first geometry into two touching rectangles. The interior line would then actually be two coinciding sides. Or you could try to model the interior line as a spike running into the rectangle e.g. from the bottom to the top and immediately back again (a degenerated inwards dent), i.e. POLYGON((-1 -1, 0.6 -1, 0.6 1, 0.6 -1, 1 -1, 1 1, -1 1))coproc

1 Answers

1
votes

The inner line can be modeled as a spike from e.g. the bottom. This approximation works:

boost::geometry::read_wkt(
    "POLYGON((-1 -1, 0.6 -1, 0.6 1, 0.60000000000001 -1, 1 -1, 1 1, -1 1))", p1);

Two polygons are created: the small lower right almost-rectangle (0.60000000000001 -1, 1 -1, 1 -0.5, 0.6 -0.5) is not connected to the rest.

This exact list of points

boost::geometry::read_wkt(
    "POLYGON((-1 -1, 0.6 -1, 0.6 1, 0.6 -1, 1 -1, 1 1, -1 1))", p1);

raises an exception because of a self intersection. When jumping over the check for self intersection we get a result, but it is incomplete (only the bigger of the two above polygons is computed).

What would, of course, also work, is splitting the polygon p1 into two rectangles:

boost::geometry::read_wkt(
    "POLYGON((-1 -1, 0.6 -1, 0.6 1, -1 1))", p11);
boost::geometry::read_wkt(
    "POLYGON((0.6 -1, 1 -1, 1 1, 0.6 1))", p12);

Then computing each difference with p2 and joining the results gives the exact expected answer (as three separate rectangles).