diff options
Diffstat (limited to 'src/boost/libs/polygon/example/voronoi_visualizer.cpp')
-rw-r--r-- | src/boost/libs/polygon/example/voronoi_visualizer.cpp | 509 |
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" |