Open
Description
Proposal
I was poking around with General_polygon_set_2
and Arr_circle_segment_traits_2
, and I wanted to display such polygons in a QGraphicsView
. So i wrote a function that convert such polygons to QPainterPath
. This way the polygons can easily be inserted into a QGraphicsScene
using QGraphicsPathItem
. This has been tested with extensive input data sets.
This function could be added to CGAL::Qt::Converter
, after being made templatised on a Traits_2
.
Would you be interested if i do a pull request?
Source Code
#include <boost/function_output_iterator.hpp>
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <CGAL/Gps_circle_segment_traits_2.h>
#include <CGAL/General_polygon_set_2.h>
#include <QtGui/QPainterPath>
#include <QWidgets/QGraphicsScene>
#include <QWidgets/QGraphicsScene>
#include <QWidgets/QGraphicsView>
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
typedef CGAL::Gps_circle_segment_traits_2<Kernel> Traits_2;
typedef CGAL::General_polygon_set_2<Traits_2> Polygon_set_2;
typedef Traits_2::General_polygon_2 Polygon_2;
typedef Traits_2::General_polygon_with_holes_2 Polygon_with_holes_2;
typedef Traits_2::Curve_2 Curve_2;
typedef Traits_2::X_monotone_curve_2 X_monotone_curve_2;
static QPainterPath construct_path(const Polygon_2 &pgn)
{
QPainterPath result;
Q_ASSERT(pgn.orientation() == CGAL::CLOCKWISE ||
pgn.orientation() == CGAL::COUNTERCLOCKWISE);
// Degenerate polygon, ring.size() < 3
if (pgn.orientation() == CGAL::ZERO) {
qWarning() << "construct_path: Ignoring degenerated polygon";
return result;
}
const bool isClockwise = pgn.orientation() == CGAL::CLOCKWISE;
Polygon_2::Curve_const_iterator current = pgn.curves_begin();
Polygon_2::Curve_const_iterator end = pgn.curves_end();
result.moveTo(CGAL::to_double(current->source().x()),
CGAL::to_double(current->source().y()));
do {
const Polygon_2::X_monotone_curve_2 &curve = *current;
const auto &source = curve.source();
const auto &target = curve.target();
if (curve.is_linear()) {
result.lineTo(QPointF(CGAL::to_double(target.x()),
CGAL::to_double(target.y())));
}
else if (curve.is_circular()) {
const auto bbox = curve.supporting_circle().bbox();
const QRectF rect(QPointF(bbox.xmin(), bbox.ymin()),
QPointF(bbox.xmax(), bbox.ymax()));
const auto center = curve.supporting_circle().center();
const double asource = qAtan2(CGAL::to_double(source.y() - center.y()),
CGAL::to_double(source.x() - center.x()));
const double atarget = qAtan2(CGAL::to_double(target.y() - center.y()),
CGAL::to_double(target.x() - center.x()));
double aspan = atarget - asource;
if (aspan < -CGAL_PI || (qFuzzyCompare(aspan, -CGAL_PI) && !isClockwise))
aspan += 2.0*CGAL_PI;
else if (aspan > CGAL_PI || (qFuzzyCompare(aspan, CGAL_PI) && isClockwise))
aspan -= 2.0*CGAL_PI;
result.arcTo(rect, qRadiansToDegrees(-asource), qRadiansToDegrees(-aspan));
}
else { // ?!?
Q_UNREACHABLE();
}
} while (++current != end);
return result;
}
Demo code
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QGraphicsScene scene;
Polygon_set_2 S;
S.join(construct_polygon(Circle_2(Point_2(0.5, 0.5), 1)));
S.join(construct_polygon(Circle_2(Point_2(5.5, 0.5), 1)));
S.join(construct_polygon(Circle_2(Point_2(5, 5), 1)));
S.join(construct_polygon(Circle_2(Point_2(1, 5), 1)));
S.join(construct_polygon(Point_2(1, 0), Point_2(5, 0),
Point_2(5, 2), Point_2(1, 2)));
S.join(construct_polygon(Point_2(1, 4), Point_2(5, 4),
Point_2(5, 6), Point_2(1, 6)));
S.join(construct_polygon(Point_2(0, 1), Point_2(2, 1),
Point_2(2, 5), Point_2(0, 5)));
S.join(construct_polygon(Point_2(4, 1), Point_2(6, 1),
Point_2(6, 5), Point_2(4, 5)));
S.join(construct_polygon(Circle_2(Point_2(8, 2.5), 1)));
S.join(construct_polygon(Circle_2(Point_2(9, 2.5), 1)));
S.join(construct_polygon(Circle_2(Point_2(10, 2.5), 1)));
S.join(construct_polygon(Circle_2(Point_2(9, 5), 1)));
S.join(construct_polygon(Circle_2(Point_2(3, 1.5), 1)));
S.join(construct_polygon(Circle_2(Point_2(3, 4.5), 1)));
S.join(construct_polygon(Circle_2(Point_2(1.5, 3), 1)));
S.join(construct_polygon(Circle_2(Point_2(4.5, 3), 1)));
// Invert the above and "capture" them into a box
// This allow to test for CW polygons with various arc configuration
S.complement();
S.intersection(construct_polygon(Point_2(-1, -1), Point_2(13, -1),
Point_2(13, 7), Point_2(-1, 7)));
// Insert a copy of the first polygons, placed above the previous box
// This allow to test for CCW polygons with various arc configuration
S.join(construct_polygon(Circle_2(Point_2(0.5, 0.5+10), 1)));
S.join(construct_polygon(Circle_2(Point_2(5.5, 0.5+10), 1)));
S.join(construct_polygon(Circle_2(Point_2(5, 5+10), 1)));
S.join(construct_polygon(Circle_2(Point_2(1, 5+10), 1)));
S.join(construct_polygon(Point_2(1, 0+10), Point_2(5, 0+10),
Point_2(5, 2+10), Point_2(1, 2+10)));
S.join(construct_polygon(Point_2(1, 4+10), Point_2(5, 4+10),
Point_2(5, 6+10), Point_2(1, 6+10)));
S.join(construct_polygon(Point_2(0, 1+10), Point_2(2, 1+10),
Point_2(2, 5+10), Point_2(0, 5+10)));
S.join(construct_polygon(Point_2(4, 1+10), Point_2(6, 1+10),
Point_2(6, 5+10), Point_2(4, 5+10)));
S.join(construct_polygon(Circle_2(Point_2(8, 2.5+10), 1)));
S.join(construct_polygon(Circle_2(Point_2(9, 2.5+10), 1)));
S.join(construct_polygon(Circle_2(Point_2(10, 2.5+10), 1)));
S.join(construct_polygon(Circle_2(Point_2(9, 5+10), 1)));
S.join(construct_polygon(Circle_2(Point_2(3, 1.5+10), 1)));
S.join(construct_polygon(Circle_2(Point_2(3, 4.5+10), 1)));
S.join(construct_polygon(Circle_2(Point_2(1.5, 3+10), 1)));
S.join(construct_polygon(Circle_2(Point_2(4.5, 3+10), 1)));
// Insert the resulting polygons into the graphics scene
S.polygons_with_holes(boost::make_function_output_iterator([&scene](const Polygon_with_holes_2 &pgn) {
if (!pgn.is_unbounded())
scene.addPath(construct_path(pgn.outer_boundary()), QPen(Qt::green, 0.0), Qt::darkGreen);
Polygon_with_holes_2::Hole_const_iterator current = pgn.holes_begin();
Polygon_with_holes_2::Hole_const_iterator end = pgn.holes_end();
while (current != end) {
scene.addPath(construct_path(*current), QPen(Qt::red, 0.0), Qt::darkRed);
current++;
}
}));
// And show the result
QGraphicsView view;
view.setBackgroundBrush(QColor("#073642"));
view.setInteractive(true);
view.setDragMode(QGraphicsView::ScrollHandDrag);
scene.setSceneRect(scene.itemsBoundingRect());
view.setScene(&scene);
view.fitInView(scene.sceneRect(), Qt::KeepAspectRatio);
view.scale(7, -7); // Revert Y-axis
view.show();
return app.exec();
}