Как я могу использовать геометрию повышения С++ для создания кольца (бублика) из двух полигонов?

Я пытаюсь вычислить разницу между 2 многоугольниками (на самом деле прямолинейными формами для простоты). Например, shape1 имеет список точек {0 0, 100, 0, 100 100, 0 100}, а shape2 имеет список точек {25 25, 75 25, 75 75, 25 75}. Итак, по концепции я ожидаю, что "shape1 - shape2" предоставит мне 4 прямоугольных коробки, которые могут иметь форму кольца или пончика. Я не знаю, как этого добиться, но я нашел в Интернете библиотеку «ускорения» и попробовал это так:

введите здесь описание изображения

#include <iostream>
#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::polygon<boost::geometry::model::d2::point_xy<double> > polygon;

    polygon green, blue;

    boost::geometry::read_wkt( "POLYGON((0 0 100 0 100 100 0 100))", green);

    boost::geometry::read_wkt( "POLYGON((25 25 75 22 75 75 25 75))", blue);

    std::list<polygon> output;
    boost::geometry::difference(green, blue, output);

    int i = 0;
    std::cout << "green - blue:" << std::endl;
    BOOST_FOREACH(polygon const& p, output)
    {
        std::cout << i++ << ": " << boost::geometry::area(p) << std::endl;
    }


    output.clear();
    boost::geometry::difference(blue, green, output);

    i = 0;
    std::cout << "blue - green:" << std::endl;
    BOOST_FOREACH(polygon const& p, output)
    {
        std::cout << i++ << ": " << boost::geometry::area(p) << std::endl;
    }


    return 0;
}

Однако ничего не распечатывалось... Мой план состоял в том, чтобы найти способ преобразовать результаты вывода в прямоугольные блоки {0 0 100 0 100 25 0 25} {0 75 100 75 100 100 0 100} {0 25 25 25 25 75 0 75} и {75 25 100 25 100 75 75 75}, но я разочарован тем, что приведенный выше код вообще ничего не печатает. Может ли кто-нибудь дать мне некоторое руководство? Я прикрепил картинку, показывающую, что я хочу сделать. На самом деле, у меня уже есть все координаты точек для представления этого пончика, так что, может быть, я могу пропустить «функцию Difference()»? Если это так, трудная часть будет состоять в том, чтобы преобразовать пончик в прямоугольные сегменты. (Предположим, что все многоугольники здесь имеют прямолинейную форму.) Спасибо.


person Community    schedule 07.12.2017    source источник
comment
Если это так, трудной задачей будет преобразование пончика в прямоугольные сегменты. Многоугольники (определение OGC) в любом случае могут иметь отверстия, см. мой второй ответ   -  person sehe    schedule 07.12.2017


Ответы (2)


другой ответ положит конец вашему разочарованию/замешательству, этот ответ сделает вас более продуктивным :)

И, да, вы можете пропустить функцию отличия:

bg::read_wkt("POLYGON((0 0 0 100 100 100 100 0 0 0) (25 25 75 22 75 75 25 75 25 25))", donut);

Это определяет внутреннее кольцо (в обратной ориентации!).

Результат:

введите здесь описание изображения

Генерируется этой программой:

Прямой эфир на Coliru

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

#include <iostream>
#include <fstream>

namespace bg = boost::geometry; 

int main() {
    typedef bg::model::d2::point_xy<double> point;
    typedef bg::model::polygon<point> polygon;

    polygon donut;
    bg::read_wkt("POLYGON((0 0 0 100 100 100 100 0 0 0) (25 25 75 22 75 75 25 75 25 25))", donut);

    std::ofstream svg("output.svg");
    boost::geometry::svg_mapper<point> mapper(svg, 400, 400);
    mapper.add(donut);

    mapper.map(donut, "fill-opacity:0.5;fill:rgb(0,0,153);stroke:rgb(0,0,200);stroke-width:2");
}
person sehe    schedule 07.12.2017

Ваши начальные полигоны не имеют требуемой ориентации. Вы можете убедиться в этом сами с помощью is_valid. Удобно, что вы можете использовать correct для устранения наиболее распространенных проблем с вашими входными данными:

std::string reason;
if (!bg::is_valid(geometry, reason))
{
    std::cout << "Correcting " << bg::wkt(geometry) << " to ";
    bg::correct(geometry);
    std::cout << bg::wkt(geometry) << "\n";

    if (!bg::is_valid(geometry, reason))
        std::cout << "UNCORRECTIBLE: " << reason << "\n";
}

Когда вы это сделаете, вы обнаружите:

Correcting POLYGON((0 0,100 0,100 100,0 100,0 0)) to POLYGON((0 0,0 100,100 100,100 0,0 0))
Correcting POLYGON((25 25,75 22,75 75,25 75,25 25)) to POLYGON((25 25,25 75,75 75,75 22,25 25))

Теперь, когда вы получите разницу, вы получите ожидаемый результат:

auto do_diff = [](std::string caption, auto const& a, auto const& b) {
    multi output;
    bg::difference(a, b, output);

    std::cout << caption << bg::wkt(output) << std::endl;
};

do_diff("green - blue:", green, blue);
do_diff("blue - green:", blue, green);

Полная демонстрация

Жить на Coliru

#include <iostream>
#include <fstream>

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

#include <boost/foreach.hpp>

namespace bg = boost::geometry; 

int main() {
    typedef bg::model::d2::point_xy<double> point;
    typedef bg::model::polygon<point> polygon;
    typedef bg::model::multi_polygon<polygon> multi;

    polygon green, blue;

    bg::read_wkt("POLYGON((0 0 100 0 100 100 0 100))", green);
    bg::read_wkt("POLYGON((25 25 75 22 75 75 25 75))", blue);

    auto test = [](polygon& geometry) {
        std::string reason;
        if (!bg::is_valid(geometry, reason))
        {
            std::cout << "Correcting " << bg::wkt(geometry) << " to ";
            bg::correct(geometry);
            std::cout << bg::wkt(geometry) << "\n";

            if (!bg::is_valid(geometry, reason))
                std::cout << "UNCORRECTIBLE: " << reason << "\n";
        }
    };

    test(green);
    test(blue);

    auto do_diff = [](std::string caption, polygon const& a, polygon const& b) {
        multi output;
        bg::difference(a, b, output);

        std::cout << caption << bg::wkt(output) << std::endl;
    };

    do_diff("green - blue:", green, blue);
    do_diff("blue - green:", blue, green);

    {
        std::ofstream svg("output.svg");
        boost::geometry::svg_mapper<point> mapper(svg, 400, 400);
        mapper.add(blue);
        mapper.add(green);

        mapper.map(blue, "fill-opacity:0.5;fill:rgb(0,0,153);stroke:rgb(0,0,200);stroke-width:2");
        mapper.map(green, "fill-opacity:0.5;fill:rgb(0,153,0);stroke:rgb(0,200,0);stroke-width:2");
    }
}

Отпечатки

Correcting POLYGON((0 0,100 0,100 100,0 100,0 0)) to POLYGON((0 0,0 100,100 100,100 0,0 0))
Correcting POLYGON((25 25,75 22,75 75,25 75,25 25)) to POLYGON((25 25,25 75,75 75,75 22,25 25))
green - blue:MULTIPOLYGON(((0 0,0 100,100 100,100 0,0 0),(25 25,75 22,75 75,25 75,25 25)))
blue - green:MULTIPOLYGON()

И пишет svg для:

введите здесь описание изображения

person sehe    schedule 07.12.2017
comment
Могу я спросить еще кое-что? Существует ли метод в геометрии повышения, который позволяет мне генерировать прямоугольные сегменты из прямолинейного пончика? Этот пример представляет собой квадратную форму, но в целом форма прямолинейного пончика может выглядеть как L или T. - person ; 07.12.2017
comment
Думаю, это заслуживает отдельного вопроса. у меня нет ответа на этот вопрос - person sehe; 07.12.2017