2
0
mirror of https://github.com/boostorg/polygon.git synced 2026-01-28 19:32:12 +00:00
Files
polygon/example/voronoi_visualizer.cpp
2012-05-07 20:17:28 +00:00

348 lines
9.9 KiB
C++

// 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 <vector>
#include <QtOpenGL/QGLWidget>
#include <QtGui/QtGui>
#include <boost/polygon/voronoi_builder.hpp>
#include <boost/polygon/voronoi_diagram.hpp>
#include <boost/polygon/voronoi_utils.hpp>
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<coordinate_type>::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<point_type> vec;
if (!it->is_finite())
voronoi_utils<coordinate_type>::clip(*it, brect_, vec);
else {
coordinate_type max_error = 1E-3 * (brect_.x_max() - brect_.x_min());
voronoi_utils<coordinate_type>::discretize(*it, max_error, vec);
}
for (int i = 0; i < static_cast<int>(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<double> point_type;
typedef voronoi_diagram<double> 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<double>::vertex_type* v = edge->vertex1();
if (v == NULL || !edge->is_primary())
return;
const voronoi_diagram<double>::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<double> brect_;
point_type shift_;
default_voronoi_builder vb_;
voronoi_diagram<coordinate_type> 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"