summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/polygon/example/voronoi_visualizer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/libs/polygon/example/voronoi_visualizer.cpp')
-rw-r--r--src/boost/libs/polygon/example/voronoi_visualizer.cpp509
1 files changed, 509 insertions, 0 deletions
diff --git a/src/boost/libs/polygon/example/voronoi_visualizer.cpp b/src/boost/libs/polygon/example/voronoi_visualizer.cpp
new file mode 100644
index 000000000..3049c3877
--- /dev/null
+++ b/src/boost/libs/polygon/example/voronoi_visualizer.cpp
@@ -0,0 +1,509 @@
+// Boost.Polygon library voronoi_visualizer.cpp file
+
+// Copyright Andrii Sydorchuk 2010-2012.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org for updates, documentation, and revision history.
+
+#include <iostream>
+#include <vector>
+
+#include <QtOpenGL/QGLWidget>
+#include <QtGui/QtGui>
+
+#include <boost/polygon/polygon.hpp>
+#include <boost/polygon/voronoi.hpp>
+using namespace boost::polygon;
+
+#include "voronoi_visual_utils.hpp"
+
+class GLWidget : public QGLWidget {
+ Q_OBJECT
+
+ public:
+ explicit GLWidget(QMainWindow* parent = NULL) :
+ QGLWidget(QGLFormat(QGL::SampleBuffers), parent),
+ primary_edges_only_(false),
+ internal_edges_only_(false) {
+ startTimer(40);
+ }
+
+ QSize sizeHint() const {
+ return QSize(600, 600);
+ }
+
+ void build(const QString& file_path) {
+ // Clear all containers.
+ clear();
+
+ // Read data.
+ read_data(file_path);
+
+ // No data, don't proceed.
+ if (!brect_initialized_) {
+ return;
+ }
+
+ // Construct bounding rectangle.
+ construct_brect();
+
+ // Construct voronoi diagram.
+ construct_voronoi(
+ point_data_.begin(), point_data_.end(),
+ segment_data_.begin(), segment_data_.end(),
+ &vd_);
+
+ // Color exterior edges.
+ for (const_edge_iterator it = vd_.edges().begin();
+ it != vd_.edges().end(); ++it) {
+ if (!it->is_finite()) {
+ color_exterior(&(*it));
+ }
+ }
+
+ // Update view port.
+ update_view_port();
+ }
+
+ void show_primary_edges_only() {
+ primary_edges_only_ ^= true;
+ }
+
+ void show_internal_edges_only() {
+ internal_edges_only_ ^= true;
+ }
+
+ protected:
+ void initializeGL() {
+ glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
+ glEnable(GL_POINT_SMOOTH);
+ }
+
+ void paintGL() {
+ qglClearColor(QColor::fromRgb(255, 255, 255));
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ draw_points();
+ draw_segments();
+ draw_vertices();
+ draw_edges();
+ }
+
+ void resizeGL(int width, int height) {
+ int side = qMin(width, height);
+ glViewport((width - side) / 2, (height - side) / 2, side, side);
+ }
+
+ void timerEvent(QTimerEvent* e) {
+ update();
+ }
+
+ private:
+ typedef double coordinate_type;
+ typedef point_data<coordinate_type> point_type;
+ typedef segment_data<coordinate_type> segment_type;
+ typedef rectangle_data<coordinate_type> rect_type;
+ typedef voronoi_builder<int> VB;
+ typedef voronoi_diagram<coordinate_type> VD;
+ typedef VD::cell_type cell_type;
+ typedef VD::cell_type::source_index_type source_index_type;
+ typedef VD::cell_type::source_category_type source_category_type;
+ typedef VD::edge_type edge_type;
+ typedef VD::cell_container_type cell_container_type;
+ typedef VD::cell_container_type vertex_container_type;
+ typedef VD::edge_container_type edge_container_type;
+ typedef VD::const_cell_iterator const_cell_iterator;
+ typedef VD::const_vertex_iterator const_vertex_iterator;
+ typedef VD::const_edge_iterator const_edge_iterator;
+
+ static const std::size_t EXTERNAL_COLOR = 1;
+
+ void clear() {
+ brect_initialized_ = false;
+ point_data_.clear();
+ segment_data_.clear();
+ vd_.clear();
+ }
+
+ void read_data(const QString& file_path) {
+ QFile data(file_path);
+ if (!data.open(QFile::ReadOnly)) {
+ QMessageBox::warning(
+ this, tr("Voronoi Visualizer"),
+ tr("Disable to open file ") + file_path);
+ }
+ QTextStream in_stream(&data);
+ std::size_t num_points, num_segments;
+ int x1, y1, x2, y2;
+ in_stream >> num_points;
+ for (std::size_t i = 0; i < num_points; ++i) {
+ in_stream >> x1 >> y1;
+ point_type p(x1, y1);
+ update_brect(p);
+ point_data_.push_back(p);
+ }
+ in_stream >> num_segments;
+ for (std::size_t i = 0; i < num_segments; ++i) {
+ in_stream >> x1 >> y1 >> x2 >> y2;
+ point_type lp(x1, y1);
+ point_type hp(x2, y2);
+ update_brect(lp);
+ update_brect(hp);
+ segment_data_.push_back(segment_type(lp, hp));
+ }
+ in_stream.flush();
+ }
+
+ void update_brect(const point_type& point) {
+ if (brect_initialized_) {
+ encompass(brect_, point);
+ } else {
+ set_points(brect_, point, point);
+ brect_initialized_ = true;
+ }
+ }
+
+ void construct_brect() {
+ double side = (std::max)(xh(brect_) - xl(brect_), yh(brect_) - yl(brect_));
+ center(shift_, brect_);
+ set_points(brect_, shift_, shift_);
+ bloat(brect_, side * 1.2);
+ }
+
+ void color_exterior(const VD::edge_type* edge) {
+ if (edge->color() == EXTERNAL_COLOR) {
+ return;
+ }
+ edge->color(EXTERNAL_COLOR);
+ edge->twin()->color(EXTERNAL_COLOR);
+ const VD::vertex_type* v = edge->vertex1();
+ if (v == NULL || !edge->is_primary()) {
+ return;
+ }
+ v->color(EXTERNAL_COLOR);
+ const VD::edge_type* e = v->incident_edge();
+ do {
+ color_exterior(e);
+ e = e->rot_next();
+ } while (e != v->incident_edge());
+ }
+
+ void update_view_port() {
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ rect_type view_rect = brect_;
+ deconvolve(view_rect, shift_);
+ glOrtho(xl(view_rect), xh(view_rect),
+ yl(view_rect), yh(view_rect),
+ -1.0, 1.0);
+ glMatrixMode(GL_MODELVIEW);
+ }
+
+ void draw_points() {
+ // Draw input points and endpoints of the input segments.
+ glColor3f(0.0f, 0.5f, 1.0f);
+ glPointSize(9);
+ glBegin(GL_POINTS);
+ for (std::size_t i = 0; i < point_data_.size(); ++i) {
+ point_type point = point_data_[i];
+ deconvolve(point, shift_);
+ glVertex2f(point.x(), point.y());
+ }
+ for (std::size_t i = 0; i < segment_data_.size(); ++i) {
+ point_type lp = low(segment_data_[i]);
+ lp = deconvolve(lp, shift_);
+ glVertex2f(lp.x(), lp.y());
+ point_type hp = high(segment_data_[i]);
+ hp = deconvolve(hp, shift_);
+ glVertex2f(hp.x(), hp.y());
+ }
+ glEnd();
+ }
+
+ void draw_segments() {
+ // Draw input segments.
+ glColor3f(0.0f, 0.5f, 1.0f);
+ glLineWidth(2.7f);
+ glBegin(GL_LINES);
+ for (std::size_t i = 0; i < segment_data_.size(); ++i) {
+ point_type lp = low(segment_data_[i]);
+ lp = deconvolve(lp, shift_);
+ glVertex2f(lp.x(), lp.y());
+ point_type hp = high(segment_data_[i]);
+ hp = deconvolve(hp, shift_);
+ glVertex2f(hp.x(), hp.y());
+ }
+ glEnd();
+ }
+
+ void draw_vertices() {
+ // Draw voronoi vertices.
+ glColor3f(0.0f, 0.0f, 0.0f);
+ glPointSize(6);
+ glBegin(GL_POINTS);
+ for (const_vertex_iterator it = vd_.vertices().begin();
+ it != vd_.vertices().end(); ++it) {
+ if (internal_edges_only_ && (it->color() == EXTERNAL_COLOR)) {
+ continue;
+ }
+ point_type vertex(it->x(), it->y());
+ vertex = deconvolve(vertex, shift_);
+ glVertex2f(vertex.x(), vertex.y());
+ }
+ glEnd();
+ }
+ void draw_edges() {
+ // Draw voronoi edges.
+ glColor3f(0.0f, 0.0f, 0.0f);
+ glLineWidth(1.7f);
+ for (const_edge_iterator it = vd_.edges().begin();
+ it != vd_.edges().end(); ++it) {
+ if (primary_edges_only_ && !it->is_primary()) {
+ continue;
+ }
+ if (internal_edges_only_ && (it->color() == EXTERNAL_COLOR)) {
+ continue;
+ }
+ std::vector<point_type> samples;
+ if (!it->is_finite()) {
+ clip_infinite_edge(*it, &samples);
+ } else {
+ point_type vertex0(it->vertex0()->x(), it->vertex0()->y());
+ samples.push_back(vertex0);
+ point_type vertex1(it->vertex1()->x(), it->vertex1()->y());
+ samples.push_back(vertex1);
+ if (it->is_curved()) {
+ sample_curved_edge(*it, &samples);
+ }
+ }
+ glBegin(GL_LINE_STRIP);
+ for (std::size_t i = 0; i < samples.size(); ++i) {
+ point_type vertex = deconvolve(samples[i], shift_);
+ glVertex2f(vertex.x(), vertex.y());
+ }
+ glEnd();
+ }
+ }
+
+ void clip_infinite_edge(
+ const edge_type& edge, std::vector<point_type>* clipped_edge) {
+ const cell_type& cell1 = *edge.cell();
+ const cell_type& cell2 = *edge.twin()->cell();
+ point_type origin, direction;
+ // Infinite edges could not be created by two segment sites.
+ if (cell1.contains_point() && cell2.contains_point()) {
+ point_type p1 = retrieve_point(cell1);
+ point_type p2 = retrieve_point(cell2);
+ origin.x((p1.x() + p2.x()) * 0.5);
+ origin.y((p1.y() + p2.y()) * 0.5);
+ direction.x(p1.y() - p2.y());
+ direction.y(p2.x() - p1.x());
+ } else {
+ origin = cell1.contains_segment() ?
+ retrieve_point(cell2) :
+ retrieve_point(cell1);
+ segment_type segment = cell1.contains_segment() ?
+ retrieve_segment(cell1) :
+ retrieve_segment(cell2);
+ coordinate_type dx = high(segment).x() - low(segment).x();
+ coordinate_type dy = high(segment).y() - low(segment).y();
+ if ((low(segment) == origin) ^ cell1.contains_point()) {
+ direction.x(dy);
+ direction.y(-dx);
+ } else {
+ direction.x(-dy);
+ direction.y(dx);
+ }
+ }
+ coordinate_type side = xh(brect_) - xl(brect_);
+ coordinate_type koef =
+ side / (std::max)(fabs(direction.x()), fabs(direction.y()));
+ if (edge.vertex0() == NULL) {
+ clipped_edge->push_back(point_type(
+ origin.x() - direction.x() * koef,
+ origin.y() - direction.y() * koef));
+ } else {
+ clipped_edge->push_back(
+ point_type(edge.vertex0()->x(), edge.vertex0()->y()));
+ }
+ if (edge.vertex1() == NULL) {
+ clipped_edge->push_back(point_type(
+ origin.x() + direction.x() * koef,
+ origin.y() + direction.y() * koef));
+ } else {
+ clipped_edge->push_back(
+ point_type(edge.vertex1()->x(), edge.vertex1()->y()));
+ }
+ }
+
+ void sample_curved_edge(
+ const edge_type& edge,
+ std::vector<point_type>* sampled_edge) {
+ coordinate_type max_dist = 1E-3 * (xh(brect_) - xl(brect_));
+ point_type point = edge.cell()->contains_point() ?
+ retrieve_point(*edge.cell()) :
+ retrieve_point(*edge.twin()->cell());
+ segment_type segment = edge.cell()->contains_point() ?
+ retrieve_segment(*edge.twin()->cell()) :
+ retrieve_segment(*edge.cell());
+ voronoi_visual_utils<coordinate_type>::discretize(
+ point, segment, max_dist, sampled_edge);
+ }
+
+ point_type retrieve_point(const cell_type& cell) {
+ source_index_type index = cell.source_index();
+ source_category_type category = cell.source_category();
+ if (category == SOURCE_CATEGORY_SINGLE_POINT) {
+ return point_data_[index];
+ }
+ index -= point_data_.size();
+ if (category == SOURCE_CATEGORY_SEGMENT_START_POINT) {
+ return low(segment_data_[index]);
+ } else {
+ return high(segment_data_[index]);
+ }
+ }
+
+ segment_type retrieve_segment(const cell_type& cell) {
+ source_index_type index = cell.source_index() - point_data_.size();
+ return segment_data_[index];
+ }
+
+ point_type shift_;
+ std::vector<point_type> point_data_;
+ std::vector<segment_type> segment_data_;
+ rect_type brect_;
+ VB vb_;
+ VD vd_;
+ bool brect_initialized_;
+ bool primary_edges_only_;
+ bool internal_edges_only_;
+};
+
+class MainWindow : public QWidget {
+ Q_OBJECT
+
+ public:
+ MainWindow() {
+ glWidget_ = new GLWidget();
+ file_dir_ = QDir(QDir::currentPath(), tr("*.txt"));
+ file_name_ = tr("");
+
+ QHBoxLayout* centralLayout = new QHBoxLayout;
+ centralLayout->addWidget(glWidget_);
+ centralLayout->addLayout(create_file_layout());
+ setLayout(centralLayout);
+
+ update_file_list();
+ setWindowTitle(tr("Voronoi Visualizer"));
+ layout()->setSizeConstraint(QLayout::SetFixedSize);
+ }
+
+ private slots:
+ void primary_edges_only() {
+ glWidget_->show_primary_edges_only();
+ }
+
+ void internal_edges_only() {
+ glWidget_->show_internal_edges_only();
+ }
+
+ void browse() {
+ QString new_path = QFileDialog::getExistingDirectory(
+ 0, tr("Choose Directory"), file_dir_.absolutePath());
+ if (new_path.isEmpty()) {
+ return;
+ }
+ file_dir_.setPath(new_path);
+ update_file_list();
+ }
+
+ void build() {
+ file_name_ = file_list_->currentItem()->text();
+ QString file_path = file_dir_.filePath(file_name_);
+ message_label_->setText("Building...");
+ glWidget_->build(file_path);
+ message_label_->setText("Double click the item to build voronoi diagram:");
+ setWindowTitle(tr("Voronoi Visualizer - ") + file_path);
+ }
+
+ void print_scr() {
+ if (!file_name_.isEmpty()) {
+ QImage screenshot = glWidget_->grabFrameBuffer(true);
+ QString output_file = file_dir_.absolutePath() + tr("/") +
+ file_name_.left(file_name_.indexOf('.')) + tr(".png");
+ screenshot.save(output_file, 0, -1);
+ }
+ }
+
+ private:
+ QGridLayout* create_file_layout() {
+ QGridLayout* file_layout = new QGridLayout;
+
+ message_label_ = new QLabel("Double click item to build voronoi diagram:");
+
+ file_list_ = new QListWidget();
+ file_list_->connect(file_list_,
+ SIGNAL(itemDoubleClicked(QListWidgetItem*)),
+ this,
+ SLOT(build()));
+
+ QCheckBox* primary_checkbox = new QCheckBox("Show primary edges only.");
+ connect(primary_checkbox, SIGNAL(clicked()),
+ this, SLOT(primary_edges_only()));
+
+ QCheckBox* internal_checkbox = new QCheckBox("Show internal edges only.");
+ connect(internal_checkbox, SIGNAL(clicked()),
+ this, SLOT(internal_edges_only()));
+
+ QPushButton* browse_button =
+ new QPushButton(tr("Browse Input Directory"));
+ connect(browse_button, SIGNAL(clicked()), this, SLOT(browse()));
+ browse_button->setMinimumHeight(50);
+
+ QPushButton* print_scr_button = new QPushButton(tr("Make Screenshot"));
+ connect(print_scr_button, SIGNAL(clicked()), this, SLOT(print_scr()));
+ print_scr_button->setMinimumHeight(50);
+
+ file_layout->addWidget(message_label_, 0, 0);
+ file_layout->addWidget(file_list_, 1, 0);
+ file_layout->addWidget(primary_checkbox, 2, 0);
+ file_layout->addWidget(internal_checkbox, 3, 0);
+ file_layout->addWidget(browse_button, 4, 0);
+ file_layout->addWidget(print_scr_button, 5, 0);
+
+ return file_layout;
+ }
+
+ void update_file_list() {
+ QFileInfoList list = file_dir_.entryInfoList();
+ file_list_->clear();
+ if (file_dir_.count() == 0) {
+ return;
+ }
+ QFileInfoList::const_iterator it;
+ for (it = list.begin(); it != list.end(); it++) {
+ file_list_->addItem(it->fileName());
+ }
+ file_list_->setCurrentRow(0);
+ }
+
+ QDir file_dir_;
+ QString file_name_;
+ GLWidget* glWidget_;
+ QListWidget* file_list_;
+ QLabel* message_label_;
+};
+
+int main(int argc, char* argv[]) {
+ QApplication app(argc, argv);
+ MainWindow window;
+ window.show();
+ return app.exec();
+}
+
+#include "voronoi_visualizer.moc"