1

I have three types of queries for a polygon to implement using boost geometry:

  1. translating a polygon to a given point
  2. rotating a polygon about a reference point(not necessarily about origin)
  3. reflecting a polygon around a line

As I am new to Boost Geomtry I am facing problems understanding the syntax. I searched for examples that satisfies my queries but not quite found one or found something that hard to understand for me. Could you please give any examples code that implement the queries with little explanation?

Christopher Moore
  • 15,626
  • 10
  • 42
  • 52

1 Answers1

1

The most generic transform I know of in the library is the matrix transform, which is a strategy you can use with transform.

Let's generate some random rectangles, rotated by random angles, translated over (-500..500, -500..500) and scaled between 1..3:

polygon gen_rectangle() {
    using box = bgm::box<point_xy>;
    polygon raw, result;
    box initial { {0, 0}, { rand(1, 1'000), rand(1, 1'000) } };
    bg::correct(raw);
    bg::assign(raw, initial);

    using namespace bg::strategy::transform;
    auto rot   = rand(-M_PI, +M_PI);
    auto scale = rand(1.0, 3.0);
    auto x     = rand(-500.0, 500.0),
         y     = rand(-500.0, 500.0);

    matrix_transformer<double, 2, 2> xfrm(
            scale* cos(rot), scale*sin(rot), x,
            scale*-sin(rot), scale*cos(rot), y,
            0,              0, 1);

    boost::geometry::transform(raw, result, xfrm);
    return result;
}

Writing some frames:

int main(int argc, char** argv) {
    auto const seed = argc>1? std::stoul(argv[1]) : std::random_device{}();
    prng.seed(seed);

    // generate shapes
    for (int frame = 0; frame < 30; ++frame) {
        multi_polygon shapes, merged;
        std::generate_n(back_inserter(shapes), 10, gen_rectangle);
        save_frame(shapes, frame);
    }
}

Results in:

enter image description here

Mirroring In A Line

I don't think that's covered with that transform (although you might be able to express any of these with a suitable translation, followed by a rotation and another translation?).

I'd attack that by a point-wise transform, where you do the projection of a point on a line (see e.g. How to find two points that form closest distance between two rectangles?, but less complicated because you can assume infinite lines, not segments), and extending the same distance on the other side.

Full Demo Code

Live On Coliru

#include <boost/geometry.hpp>
#include <boost/geometry/strategies/transform/matrix_transformers.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/geometries/multi_polygon.hpp>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <random>

namespace bg  = boost::geometry;
namespace bgm = bg::model;

using point_xy      = bgm::d2::point_xy<double>;
using polygon       = bgm::polygon<point_xy>;
using multi_polygon = bgm::multi_polygon<polygon>;

static std::mt19937 prng;
void save_frame(multi_polygon const& p, int frameno);
polygon gen_rectangle();

int main(int argc, char** argv) {
    auto const seed = argc>1? std::stoul(argv[1]) : std::random_device{}();
    prng.seed(seed);

    // generate shapes
    for (int frame = 0; frame < 30; ++frame) {
        multi_polygon shapes, merged;
        std::generate_n(back_inserter(shapes), 10, gen_rectangle);
        save_frame(shapes, frame);
    }
}

static inline double rand(double b, double e) { return std::uniform_real_distribution<double>(b, e)(prng); }

// generate rectangle shape with varying sizes, positions and rotations
polygon gen_rectangle() {
    using box = bgm::box<point_xy>;
    polygon raw, result;
    box initial { {0, 0}, { rand(1, 1'000), rand(1, 1'000) } };
    bg::assign(raw, initial);

    using namespace bg::strategy::transform;
    double rot   = rand(-M_PI, +M_PI);
    double scale = rand(1.0, 3.0);
    double x     = rand(-500.0, 500.0),
           y     = rand(-500.0, 500.0);

    matrix_transformer<double, 2, 2> xfrm(
            scale* cos(rot), scale*sin(rot), x,
            scale*-sin(rot), scale*cos(rot), y,
            0,              0, 1);

    boost::geometry::transform(raw, result, xfrm);
    return result;
}

void save_frame(multi_polygon const& p, int frameno) {
    std::ostringstream name;
    name << "frame" << std::setw(4) << std::setfill('0') << frameno << ".svg";
    std::ofstream ofs(name.str());
    bg::svg_mapper<point_xy> mapper(ofs, 400, 400);

    mapper.add(p);
    mapper.map(p, "fill-opacity:0.5;fill:rgb(204,153,0);stroke:rgb(204,153,0);stroke-width:1", 5);
}

sehe
  • 374,641
  • 47
  • 450
  • 633
  • Thanks for your answer. But I wonder is there any built in library method Boost.Geometry has for reflection of a point/polygon? – Masum Bhuiyan Jul 05 '20 at 00:13
  • That's not a but. That was your original question. If I thought there was, I'd tell you before. Surely if someone else knows, they'll answer as well :) – sehe Jul 05 '20 at 00:14
  • Could you suggest any good resources to learn Boost.Geometry library from basic to advance? – Masum Bhuiyan Jul 05 '20 at 00:15
  • Sadly, no. They have an above-average mailing list that you may find interesting. Their authors are quite helpful, but rarely active on [SO] – sehe Jul 05 '20 at 00:33