123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509 |
- // 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"
|