Boost-геометрия: определение многоугольника

Не могли бы вы сказать мне, почему это определение полигона не работает?

namespace bg = boost::geometry;

int main()
{
typedef bg::model::point<double, 2, bg::cs::cartesian> point_type;
typedef bg::model::polygon<point_type> polygon_type;

polygon_type P;

int xi[] = {0,100,100,0,0};
int yi[] = {0,0,100,100,0};

bg::append(P, bg::make<point_type>(*xi, *yi));

double area = bg::area(P);
std::cout << "Area:" << area << std::endl;

Return 0; }

Это показывает Площадь: 0

Спасибо


person Ella    schedule 29.12.2017    source источник


Ответы (1)


Научитесь использовать библиотеку для диагностики ваших проблем:

std::string reason;
bool ok = bg::is_valid(P, reason);
std::cout << "Polygon " << (ok?"valid":"invalid") << " (" << reason << ")\n";

Отпечатки: Жить на Coliru

Polygon invalid (Geometry has too few points)

Вы также можете распечатать геометрию в формате WKT/DSV (или даже SVG): Живите на Колиру

POLYGON((0 0)) invalid (Geometry has too few points)
Area:0

Это делает проблему еще более очевидной.


Вы хотите добавить не одну точку, а кольцо. Самый простой способ добиться этого — явно сделать его кольцом:

ring_type points {
    {   0,   0 },
    { 100,   0 },
    { 100, 100 },
    {   0, 100 },
    {   0,   0 },
};

bg::append(P, points);

Все еще плохо, но лучше: Жить на Coliru

POLYGON((0 0,100 0,100 100,0 100,0 0)) invalid (Geometry has wrong orientation)
Area:-10000

Как видите, мы ошиблись с ориентацией (должно быть по часовой стрелке):

ring_type points {
    {   0,   0 },
    {   0, 100 },
    { 100, 100 },
    { 100,   0 },
    {   0,   0 },
};

Отпечатки: Жить на Coliru

POLYGON((0 0,0 100,100 100,100 0,0 0)) valid (Geometry is valid)
Area:10000

Примечание. Вы можете использовать bg::correct для устранения проблем с достоверностью в простых случаях, таких как этот.

Стиль и типы

На самом деле кольцевой тип является внешним кольцевым типом многоугольного типа:

static_assert(std::is_same<ring_type, polygon_type::ring_type>{}, "synonyms");
static_assert(bg::point_order<ring_type>::value == bg::order_selector::clockwise, "orientation");

Следовательно, вы можете построить непосредственно из инициализатора внешнего кольца:

polygon_type P { {
    {   0,   0 },
    {   0, 100 },
    { 100, 100 },
    { 100,   0 },
    {   0,   0 },
} };

Сжатие всей программы до одной строки: Live On Coliru

int main() {
    typedef bgm::polygon<bgm::d2::point_xy<double> > polygon_type;
    std::cout << "Area:" << bg::area(polygon_type { { {0, 0}, {0, 100}, {100, 100}, {100, 0}, {0, 0} } }) << std::endl;
}

Или вы действительно можете прочитать его на WKT/DSV: Live On Coliru

int main() {
    bgm::polygon<bgm::d2::point_xy<double> > P;
    bg::read_wkt("POLYGON((0 0,0 100,100 100,100 0,0 0))", P);
    std::cout << "Area:" << bg::area(P) << std::endl;
}

Все еще печатаю

Area:10000
person sehe    schedule 29.12.2017