// 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 #include #include #include #include #include using namespace boost::polygon; class GLWidget : public QGLWidget { Q_OBJECT public: 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(QString file_path) { brect_.clear(); vb_.clear(); vd_.clear(); // Open file. QFile data(file_path); if (!data.open(QFile::ReadOnly)) { QMessageBox::warning(this, tr("Voronoi Visualizer"), tr("Disable to open file ") + file_path); } // Read points from the file. QTextStream in_stream(&data); int num_point_sites = 0; int num_edge_sites = 0; int x1, y1, x2, y2; in_stream >> num_point_sites; for (int i = 0; i < num_point_sites; ++i) { in_stream >> x1 >> y1; vb_.insert_point(x1, y1); brect_.update(x1, y1); } in_stream >> num_edge_sites; for (int i = 0; i < num_edge_sites; ++i) { in_stream >> x1 >> y1 >> x2 >> y2; vb_.insert_segment(x1, y1, x2, y2); brect_.update(x1, y1); brect_.update(x2, y2); } in_stream.flush(); // Build voronoi diagram. vb_.construct(&vd_); brect_ = voronoi_utils::scale(brect_, 1.4); shift_ = point_type((brect_.x_min() + brect_.x_max()) * 0.5, (brect_.y_min() + brect_.y_max()) * 0.5); for (const_edge_iterator it = vd_.edges().begin(); it != vd_.edges().end(); ++it) { if (!it->is_finite()) { remove_exterior(&(*it)); } } // Update view. 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 voronoi sites. { glColor3f(0.0f, 0.5f, 1.0f); glPointSize(9); glBegin(GL_POINTS); for (const_cell_iterator it = vd_.cells().begin(); it != vd_.cells().end(); ++it) { if (!it->contains_segment()) { glVertex2f(it->point0().x() - shift_.x(), it->point0().y() - shift_.y()); } } glEnd(); glPointSize(6); glLineWidth(2.7f); glBegin(GL_LINES); for (const_cell_iterator it = vd_.cells().begin(); it != vd_.cells().end(); ++it) { if (it->contains_segment()) { glVertex2f(it->point0().x() - shift_.x(), it->point0().y() - shift_.y()); glVertex2f(it->point1().x() - shift_.x(), it->point1().y() - shift_.y()); } } glEnd(); glLineWidth(1.0); } // Draw voronoi vertices. /*{ glColor3f(0.0f, 0.0f, 0.0f); glBegin(GL_POINTS); for (const_vertex_iterator it = vd_.vertices().begin(); it != vd_.vertices().end(); ++it) { glVertex2f(it->vertex().x() - shift_.x(), it->vertex().y() - shift_.y()); } glEnd(); }*/ // Draw voronoi edges. { glColor3f(0.0f, 0.0f, 0.0f); glLineWidth(1.7f); glBegin(GL_LINES); 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->data()) { continue; } std::vector vec; if (!it->is_finite()) voronoi_utils::clip(*it, brect_, vec); else { coordinate_type max_error = 1E-3 * (brect_.x_max() - brect_.x_min()); voronoi_utils::discretize(*it, max_error, vec); } for (int i = 0; i < static_cast(vec.size()) - 1; ++i) { glVertex2f(vec[i].x() - shift_.x(), vec[i].y() - shift_.y()); glVertex2f(vec[i+1].x() - shift_.x(), vec[i+1].y() - shift_.y()); } } glEnd(); } } void resizeGL(int width, int height) { int side = qMin(width, height); glViewport((width - side) / 2, (height - side) / 2, side, side); } void timerEvent(QTimerEvent *) { update(); } private: typedef double coordinate_type; typedef detail::point_2d point_type; typedef voronoi_diagram VD; 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; void remove_exterior(const VD::edge_type* edge) { if (edge->data()) return; edge->data(&edge); edge->twin()->data(&edge); const voronoi_diagram::vertex_type* v = edge->vertex1(); if (v == NULL || !edge->is_primary()) return; const voronoi_diagram::edge_type* e = v->incident_edge(); do { remove_exterior(e); e = e->rot_next(); } while (e != v->incident_edge()); } void update_view_port() { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(brect_.x_min() - shift_.x(), brect_.x_max() - shift_.x(), brect_.y_min() - shift_.y(), brect_.y_max() - shift_.y(), -1.0, 1.0); glMatrixMode(GL_MODELVIEW); } bounding_rectangle brect_; point_type shift_; default_voronoi_builder vb_; voronoi_diagram vd_; 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"