1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
|
// ************************************************************************************************
//
// BornAgain: simulate and fit reflection and scattering
//
//! @file Device/Mask/Polygon.cpp
//! @brief Implements class Polygon.
//!
//! @homepage http://www.bornagainproject.org
//! @license GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2018
//! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
// ************************************************************************************************
#include "Device/Mask/Polygon.h"
#include "Base/Axis/Bin.h"
#include "Base/Util/Assert.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#include <boost/geometry.hpp>
#pragma clang diagnostic pop
//! The private data for polygons to hide boost dependency from the header
class PolygonPrivate {
public:
using point_t = boost::geometry::model::d2::point_xy<double>;
using polygon_t = boost::geometry::model::polygon<point_t>;
PolygonPrivate(const std::vector<double>& x, const std::vector<double>& y);
PolygonPrivate(const std::vector<std::pair<double, double>>& pts);
polygon_t polygon;
void get_points(std::vector<double>& xpos, std::vector<double>& ypos); // TODO const or no-&
};
PolygonPrivate::PolygonPrivate(const std::vector<double>& x, const std::vector<double>& y)
{
ASSERT(x.size() == y.size());
std::vector<point_t> points;
for (size_t i = 0; i < x.size(); ++i)
points.emplace_back(x[i], y[i]);
boost::geometry::assign_points(polygon, points);
boost::geometry::correct(polygon);
}
PolygonPrivate::PolygonPrivate(const std::vector<std::pair<double, double>>& pts)
{
std::vector<point_t> points;
points.reserve(pts.size());
for (const std::pair<double, double>& p : pts)
points.emplace_back(p.first, p.second);
boost::geometry::assign_points(polygon, points);
boost::geometry::correct(polygon);
}
void PolygonPrivate::get_points(std::vector<double>& xpos, std::vector<double>& ypos)
{
xpos.clear();
ypos.clear();
for (auto& it : polygon.outer()) {
// for vectors of x and y, extract the x/y from the point
xpos.push_back(boost::geometry::get<0>(it));
ypos.push_back(boost::geometry::get<1>(it));
}
}
// ************************************************************************************************
// IMPORTANT Input parameter is not "const reference" to be able to work from python
// (auto conversion of python list to vector<pair<double,double>>).
//! If polygon is unclosed (the last point doesn't repeat the first one), it will
//! be closed automatically.
//! @param points Two dimensional vector of (x,y) coordinates of polygon points.
Polygon::Polygon(const std::vector<std::pair<double, double>> points)
: IShape2D("Polygon")
, m_d(new PolygonPrivate(points))
{
}
Polygon::Polygon(const PolygonPrivate* d)
: IShape2D("Polygon")
, m_d(new PolygonPrivate(*d))
{
}
Polygon::~Polygon()
{
delete m_d;
}
bool Polygon::contains(double x, double y) const
{
// including borders
return boost::geometry::covered_by(PolygonPrivate::point_t(x, y), m_d->polygon);
}
bool Polygon::contains(const Bin1D& binx, const Bin1D& biny) const
{
// Test for n*n points per pixel, while waiting for a more intelligent implementation.
const int n = 5;
for (int ix = 0; ix < n; ++ix)
for (int iy = 0; iy < n; ++iy)
if (contains(binx.atFraction(ix / (n - 1.)), biny.atFraction(iy / (n - 1.))))
return true;
return false;
}
double Polygon::getArea() const
{
return boost::geometry::area(m_d->polygon);
}
void Polygon::getPoints(std::vector<double>& xpos, std::vector<double>& ypos) const
{
m_d->get_points(xpos, ypos);
}
void Polygon::print(std::ostream& ostr) const
{
ostr << boost::geometry::wkt<PolygonPrivate::polygon_t>(m_d->polygon);
}
|