diff options
author | salinasd <salinasd@636b058d-ea47-450e-bf9e-a15bfbe3eedb> | 2015-01-27 10:20:13 +0000 |
---|---|---|
committer | salinasd <salinasd@636b058d-ea47-450e-bf9e-a15bfbe3eedb> | 2015-01-27 10:20:13 +0000 |
commit | f527cde6342c5b8109a20f0a6b483327c6569844 (patch) | |
tree | 1c0464b56b21ef7767f814b9a35a6e5c68aa7613 | |
parent | df6c26bdcb28805e8949d08dad5acd012e91ecb8 (diff) |
Merge GudhUI, a UI for gudhi based on Qt
git-svn-id: svn+ssh://scm.gforge.inria.fr/svnroot/gudhi/trunk@427 636b058d-ea47-450e-bf9e-a15bfbe3eedb
Former-commit-id: 17fedd974f14a8225b27d94361e835964eeb5cba
41 files changed, 3683 insertions, 0 deletions
diff --git a/src/GudhUI/CMakeLists.txt b/src/GudhUI/CMakeLists.txt new file mode 100644 index 00000000..4c0c2087 --- /dev/null +++ b/src/GudhUI/CMakeLists.txt @@ -0,0 +1,80 @@ +cmake_minimum_required(VERSION 2.8) +project(GudhUI) + +#Specify Gudhi's path here +#for instance +SET(Gudhi_Path "/home/dsalinas/Documents/CodeSVN/gudhi/src/include") + +set(EXECUTABLE_OUTPUT_PATH bin/${CMAKE_BUILD_TYPE}) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -frounding-math -Wall -pedantic") + +find_package(Boost REQUIRED COMPONENTS) +find_package(CGAL COMPONENTS Qt4) +find_package(Qt4) +find_package(OpenGL) +find_package(QGLViewer) + +if ( CGAL_FOUND AND CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND ) + + set( QT_USE_QTXML TRUE ) + set( QT_USE_QTMAIN TRUE ) + set( QT_USE_QTSCRIPT TRUE ) + set( QT_USE_QTOPENGL TRUE ) + SET(Boost_USE_STATIC_LIBS ON) + SET(Boost_USE_MULTITHREAD OFF) + + INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS}) + LINK_DIRECTORIES(${Boost_LIBRARY_DIRS}) + + include(${QT_USE_FILE}) + include(${CGAL_USE_FILE}) + + include_directories (${QGLVIEWER_INCLUDE_DIR}) + include_directories(.) + include_directories(${Gudhi_Path}) + + + # qt : ui file, created wih Qt Designer ############### + set(CMAKE_CURRENT_BINARY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/gui") + qt4_wrap_ui( uis + gui/main_window.ui + gui/MenuEdgeContraction.ui + gui/KNearestNeighborsMenu.ui + gui/UniformNeighborsMenu.ui + gui/PersistenceMenu.ui + ) + + set(CMAKE_CURRENT_BINARY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/gui") + qt4_automoc( + gui/MainWindow.cpp + gui/Menu_k_nearest_neighbors.cpp + gui/Menu_uniform_neighbors.cpp + gui/Menu_edge_contraction.cpp + gui/Menu_persistence.cpp + ) + + set(CMAKE_CURRENT_BINARY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/view") + qt4_automoc(view/Viewer_instructor.cpp + view/Viewer.cpp + ) + ##################################################################### + + add_executable ( GudhUI + gui/gudhui.cpp + gui/MainWindow.cpp + gui/Menu_k_nearest_neighbors.cpp + gui/Menu_uniform_neighbors.cpp + gui/Menu_edge_contraction.cpp + gui/Menu_persistence.cpp + view/Viewer_instructor.cpp + view/Viewer.cpp + ${uis} + ) + + target_link_libraries( GudhUI ${QT_LIBRARIES} ${QGLVIEWER_LIBRARIES} ) + target_link_libraries( GudhUI ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} ) + +else() + message(STATUS "NOTICE: This demo requires CGAL, the QGLViewer, OpenGL and Qt4, and will not be compiled.") +endif() diff --git a/src/GudhUI/gui/KNearestNeighborsMenu.ui b/src/GudhUI/gui/KNearestNeighborsMenu.ui new file mode 100644 index 00000000..472db48b --- /dev/null +++ b/src/GudhUI/gui/KNearestNeighborsMenu.ui @@ -0,0 +1,150 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>KNearestNeighborsMenu</class> + <widget class="QDialog" name="KNearestNeighborsMenu"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>298</width> + <height>209</height> + </rect> + </property> + <property name="windowTitle"> + <string>k-nearest neighbors</string> + </property> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="geometry"> + <rect> + <x>50</x> + <y>160</y> + <width>171</width> + <height>32</height> + </rect> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + <widget class="QWidget" name="formLayoutWidget"> + <property name="geometry"> + <rect> + <x>30</x> + <y>10</y> + <width>229</width> + <height>84</height> + </rect> + </property> + <layout class="QFormLayout" name="formLayout_2"> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::AllNonFixedFieldsGrow</enum> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>k </string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QSpinBox" name="spinBoxK"> + <property name="maximum"> + <number>10000000</number> + </property> + <property name="value"> + <number>0</number> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Metric</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QComboBox" name="comboBoxMetric"> + <item> + <property name="text"> + <string>Ambient</string> + </property> + </item> + <item> + <property name="text"> + <string>Reduced Space</string> + </property> + </item> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="gridLayoutWidget"> + <property name="geometry"> + <rect> + <x>30</x> + <y>110</y> + <width>250</width> + <height>40</height> + </rect> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="1"> + <widget class="QPushButton" name="pushButtonCompute"> + <property name="text"> + <string>Compute</string> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QCheckBox" name="checkBoxAutoUpdate"> + <property name="text"> + <string>auto update</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>KNearestNeighborsMenu</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>KNearestNeighborsMenu</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/src/GudhUI/gui/MainWindow.cpp b/src/GudhUI/gui/MainWindow.cpp new file mode 100644 index 00000000..85745e93 --- /dev/null +++ b/src/GudhUI/gui/MainWindow.cpp @@ -0,0 +1,283 @@ +#include "MainWindow.h" + +#include <QWidget> +#include <QInputDialog> +#include <QFileDialog> + +#include <fenv.h> + + +#include "gui/Menu_k_nearest_neighbors.h" +#include "gui/Menu_uniform_neighbors.h" +#include "gui/Menu_edge_contraction.h" +#include "gui/Menu_persistence.h" + + +MainWindow::MainWindow(QWidget* parent): +menu_k_nearest_neighbors_(new Menu_k_nearest_neighbors(this)), +menu_uniform_neighbors_(new Menu_uniform_neighbors(this)), +menu_edge_contraction_(new Menu_edge_contraction(this,model_)), +menu_persistence_(new Menu_persistence(this)) +{ +#ifndef NDEBUG // catch nan +feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW); +#endif + + setupUi(this); + + viewer_instructor_ = new Viewer_instructor( + this, + this->viewer, + model_.complex_ + ); + + connectActions(); + + update_view(); +} + +void +MainWindow::closeEvent(QCloseEvent *event){ + exit(0); +} + + +void +MainWindow::connectActions(){ + QObject::connect(this->actionLoad_complex, SIGNAL(triggered()), this, + SLOT(off_file_open())); + QObject::connect(this->actionLoad_points, SIGNAL(triggered()), this, + SLOT(off_points_open())); + QObject::connect(this->actionSave_complex, SIGNAL(triggered()), this, + SLOT(off_file_save())); + QObject::connect(this->actionSave_points, SIGNAL(triggered()), this, + SLOT(off_points_save())); + + QObject::connect(this->actionShow_graph_stats, SIGNAL(triggered()), this, + SLOT(show_graph_stats())); + QObject::connect(this->actionShow_complex_stats, SIGNAL(triggered()), this, + SLOT(show_complex_stats())); + QObject::connect(this->actionShow_complex_dimension, SIGNAL(triggered()), this, + SLOT(show_complex_dimension())); + + QObject::connect(this->actionUniform_proximity_graph, SIGNAL(triggered()), this, + SLOT(build_rips_menu())); + QObject::connect(this->actionK_nearest_neighbors_graph, SIGNAL(triggered()), this, + SLOT(build_k_nearest_neighbors_menu())); + + + QObject::connect(this->actionContract_edges, SIGNAL(triggered()), this, + SLOT(contract_edge_menu())); + + QObject::connect(this->actionCollapse_vertices, SIGNAL(triggered()), this, + SLOT(collapse_vertices())); + + QObject::connect(this->actionCollapse_edges, SIGNAL(triggered()), this, + SLOT(collapse_edges())); + + QObject::connect(this->actionNoise, SIGNAL(triggered()), this, + SLOT(uniform_noise())); + QObject::connect(this->actionLloyd, SIGNAL(triggered()), this, + SLOT(lloyd())); + + + //view + QObject::connect(this->actionPoints, SIGNAL(triggered()), this->viewer_instructor_, + SLOT(change_draw_vertices())); + QObject::connect(this->actionEdges, SIGNAL(triggered()), this->viewer_instructor_, + SLOT(change_draw_edges())); + QObject::connect(this->actionTriangles, SIGNAL(triggered()), this->viewer_instructor_, + SLOT(change_draw_triangles())); + + //topology + QObject::connect(this->actionShow_homology_group, SIGNAL(triggered()), this, + SLOT(show_homology_group())); + QObject::connect(this->actionEuler_characteristic, SIGNAL(triggered()), this, + SLOT(show_euler_characteristic())); + QObject::connect(this->actionPersistence, SIGNAL(triggered()), this, + SLOT(persistence_menu())); + + + + QObject::connect(this, SIGNAL(sceneChanged()), this->viewer_instructor_, + SLOT(sceneChanged())); + +} + +void +MainWindow::init_view() const{ + viewer_instructor_->initialize_bounding_box(); + viewer_instructor_->show_entire_scene(); + update_view(); +} + + +void +MainWindow::update_view() const{ + emit (sceneChanged()); +} + + + +/** + * open a file chooser to choose an off to load + */ +void +MainWindow::off_file_open(){ + QString fileName = QFileDialog::getOpenFileName(this, tr("Open off File"), + "~/", tr("off files (*.off)")); + if (!fileName.isEmpty()){ + model_.off_file_open(fileName.toStdString()); + init_view(); + } +} + +void +MainWindow::off_points_open(){ + QString fileName = QFileDialog::getOpenFileName(this, tr("Open points in a off file"), + "~/", tr("off files (*.off)")); + if (!fileName.isEmpty()){ + model_.off_points_open(fileName.toStdString()); + init_view(); + } +} + + +/** + * open a file chooser to choose an off to save + */ +void +MainWindow::off_file_save(){ + QString fileName = QFileDialog::getOpenFileName(this, tr("Save to off File"), + "~/", tr("off files (*.off)")); + if (!fileName.isEmpty()) + { + model_.off_file_save(fileName.toStdString()); + } +} + +/** + * open a file chooser to choose an off to save + */ +void +MainWindow::off_points_save(){ + QString fileName = QFileDialog::getOpenFileName(this, tr("Save to off File"), + "~/", tr("off files (*.off)")); + if (!fileName.isEmpty()) + { + model_.off_points_save(fileName.toStdString()); + } +} + + +void +MainWindow::show_graph_stats(){ + model_.show_graph_stats(); +} + +void +MainWindow::show_complex_stats(){ + model_.show_complex_stats(); +} + +void +MainWindow::show_complex_dimension(){ + model_.show_complex_dimension(); +} + + +void +MainWindow::build_rips_menu(){ + menu_uniform_neighbors_->show(); +} + +void +MainWindow::build_rips(double alpha){ + model_.build_rips(alpha); + update_view(); +} + +void +MainWindow::build_k_nearest_neighbors_menu(){ + menu_k_nearest_neighbors_->show(); +} + +void +MainWindow::build_k_nearest_neighbors(unsigned k){ + model_.build_k_nearest_neighbors(k); + update_view(); +} + +void +MainWindow::contract_edge_menu(){ + menu_edge_contraction_->show(); +} + +void +MainWindow::contract_edges(unsigned num_collapses){ + std::cerr <<"Collapse "<<num_collapses<< " vertices\n"; + model_.contract_edges(num_collapses); + update_view(); +} + + +void +MainWindow::collapse_edges(){ + std::cerr <<"Collapse "<<100<< " edges\n"; + model_.collapse_edges(100); + update_view(); +} + + + +void +MainWindow::collapse_vertices(){ + std::cerr <<"Collapse vertices edges\n"; + model_.collapse_vertices(0); + update_view(); +} + + +void +MainWindow::uniform_noise(){ + bool ok; + double amplitude = QInputDialog::getDouble(this, tr("Uniform noise"), + tr("Amplitude:"), 0, 0, 10000, 3, &ok); + srand(time(NULL)); + if (ok) + model_.uniform_noise(amplitude); +} + + +void +MainWindow::lloyd(){ + //todo 1 ask lloyd parameters + model_.lloyd(0,0); + update_view(); +} + +void +MainWindow::show_homology_group(){ + model_.show_homology_group(); +} + +void +MainWindow::show_euler_characteristic(){ + model_.show_euler_characteristic(); +} + + + +void +MainWindow::persistence_menu(){ + menu_persistence_->show(); +} + +void +MainWindow::compute_persistence(int p,double threshold,int max_dim,double min_pers){ + model_.show_persistence(p,threshold,max_dim,min_pers); +} + + + +#include "MainWindow.moc" diff --git a/src/GudhUI/gui/MainWindow.h b/src/GudhUI/gui/MainWindow.h new file mode 100644 index 00000000..0eef29ed --- /dev/null +++ b/src/GudhUI/gui/MainWindow.h @@ -0,0 +1,97 @@ +#ifndef MAIN_WINDOW_H +#define MAIN_WINDOW_H + + +#include <QMainWindow> +#include "ui_main_window.h" +#include "model/Model.h" +#include "view/Viewer_instructor.h" + + +class Menu_k_nearest_neighbors; +class Menu_uniform_neighbors; +class Menu_edge_contraction; +class Menu_persistence; + +class MainWindow : public QMainWindow,public Ui::MainWindow{ + Q_OBJECT + +private: + Model model_; + Viewer_instructor* viewer_instructor_; + Menu_k_nearest_neighbors* menu_k_nearest_neighbors_; + Menu_uniform_neighbors* menu_uniform_neighbors_; + Menu_edge_contraction* menu_edge_contraction_; + Menu_persistence* menu_persistence_; + +public: + MainWindow(QWidget* parent = 0); + void connectActions(); + + /** + * compute the bounding box and calls update view + */ + void init_view() const; + void update_view() const; + + +protected: + void closeEvent(QCloseEvent *event); + void keyPressEvent(QKeyEvent *event){} + +public: + + public slots: + + + /** + * open a file chooser to choose an off to load + */ + void off_file_open(); + + void off_points_open(); + + /** + * open a file chooser to choose an off to save + */ + void off_file_save(); + void off_points_save(); + + void show_graph_stats(); + void show_complex_stats(); + void show_complex_dimension(); + + + void build_rips_menu(); + void build_rips(double alpha); + void build_k_nearest_neighbors_menu(); + void build_k_nearest_neighbors(unsigned k); + + + void contract_edge_menu(); + void contract_edges(unsigned num_collapses); + + + void collapse_vertices(); + void collapse_edges(); + + + void uniform_noise(); + void lloyd(); + + void show_homology_group(); + void show_euler_characteristic(); + void persistence_menu(); + void compute_persistence(int p,double threshold,int max_dim,double min_pers); + + + +public: + signals: + void sceneChanged() const; + + +}; + + +#endif diff --git a/src/GudhUI/gui/MenuEdgeContraction.ui b/src/GudhUI/gui/MenuEdgeContraction.ui new file mode 100644 index 00000000..da2e5c82 --- /dev/null +++ b/src/GudhUI/gui/MenuEdgeContraction.ui @@ -0,0 +1,118 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MenuEdgeContraction</class>
+ <widget class="QDialog" name="MenuEdgeContraction">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>362</width>
+ <height>209</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Edge contraction</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="5" column="2">
+ <widget class="QSpinBox" name="spinBox_nb_remaining_vertices">
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ <property name="maximum">
+ <number>999999999</number>
+ </property>
+ <property name="value">
+ <number>1</number>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="2">
+ <widget class="QCheckBox" name="checkBox_link_condition">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Link condition</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="2" alignment="Qt::AlignRight">
+ <widget class="QLabel" name="txt_nb_collapses">
+ <property name="text">
+ <string>1</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Policy</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="2">
+ <widget class="QComboBox" name="m_simplificationMethod">
+ <item>
+ <property name="text">
+ <string>Length_midpoint</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="2" column="2" alignment="Qt::AlignRight">
+ <widget class="QLabel" name="txt_nb_vertices">
+ <property name="text">
+ <string>0</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>Number of vertices</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" colspan="2">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Number of contractions</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0" colspan="2">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Number of vertices after </string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QSlider" name="horizontalSlider">
+ <property name="minimum">
+ <number>0</number>
+ </property>
+ <property name="maximum">
+ <number>100</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <widget class="QPushButton" name="pushButton_collapse">
+ <property name="text">
+ <string>Perform collapse</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/GudhUI/gui/Menu_edge_contraction.cpp b/src/GudhUI/gui/Menu_edge_contraction.cpp new file mode 100644 index 00000000..dd2621be --- /dev/null +++ b/src/GudhUI/gui/Menu_edge_contraction.cpp @@ -0,0 +1,91 @@ +/* + * Menu_edge_contraction.cpp + * + * Created on: Sep 11, 2014 + * Author: dsalinas + */ + +#ifndef MENU_EDGE_CONTRACTION_CPP_ +#define MENU_EDGE_CONTRACTION_CPP_ + + +#include "Menu_edge_contraction.h" + +Menu_edge_contraction::Menu_edge_contraction(MainWindow* parent,const Model& model): +parent_(parent),model_(model) +{ + setupUi(this); + connectActions(parent_); +} + +void Menu_edge_contraction::connectActions(MainWindow* parent) +{ + QObject::connect( + this->horizontalSlider, + SIGNAL(valueChanged(int)), + this, + SLOT(slider_value_changed(int)) + ); + + + QObject::connect(this, SIGNAL(contract_edges(unsigned)), parent, SLOT(contract_edges(unsigned))); + + QObject::connect(this->pushButton_collapse, SIGNAL(clicked()), this, SLOT(send_contract_edges())); + +} + +void Menu_edge_contraction::slider_value_changed(int new_slider_value){ + int num_collapses = + (horizontalSlider->value()==1)? 1 : horizontalSlider->value() * model_.num_vertices() / 100 ; + this->txt_nb_vertices->setNum((int)model_.num_vertices()); + this->txt_nb_collapses->setNum(num_collapses); + this->spinBox_nb_remaining_vertices->setValue(model_.num_vertices()-num_collapses); +} + + +void +Menu_edge_contraction::update_slider_value(){ + int num_vertices = model_.num_vertices(); + int num_collapses = (horizontalSlider->value()==1)? 1 : horizontalSlider->value() * num_vertices / 100 ; + int horizontal_slider_position = num_vertices>0? num_collapses/(double)num_vertices * 100 : 1 ; + horizontalSlider->setValue(horizontal_slider_position); +} + + +void +Menu_edge_contraction::update_gui_numbers(){ + update_slider_value(); + bool ok; + int num_collapses = this->txt_nb_collapses->text().toInt(&ok,10); + if(!ok) return; + this->txt_nb_vertices->setNum((int)model_.num_vertices()); + this->txt_nb_collapses->setNum(num_collapses); + this->spinBox_nb_remaining_vertices->setValue(model_.num_vertices()-num_collapses); +} + +void +Menu_edge_contraction::update_gui_numbers(int new_value){ + update_gui_numbers(); +} + + +void +Menu_edge_contraction::send_contract_edges(){ + emit(contract_edges(num_collapses())); + update_gui_numbers(); +} + +unsigned +Menu_edge_contraction::num_vertices(){ + return model_.num_vertices(); +} + +unsigned +Menu_edge_contraction::num_collapses(){ + return (horizontalSlider->value()==1)? 1 : horizontalSlider->value() * num_vertices() / 100 ; +} + + +#include "Menu_edge_contraction.moc" + +#endif /* MENU_EDGE_CONTRACTION_CPP_ */ diff --git a/src/GudhUI/gui/Menu_edge_contraction.h b/src/GudhUI/gui/Menu_edge_contraction.h new file mode 100644 index 00000000..e497a90f --- /dev/null +++ b/src/GudhUI/gui/Menu_edge_contraction.h @@ -0,0 +1,52 @@ +/* + * Menu_edge_contraction.h + * + * Created on: Sep 11, 2014 + * Author: dsalinas + */ + +#ifndef MENU_EDGE_CONTRACTION_H_ +#define MENU_EDGE_CONTRACTION_H_ + + +#include "gui/MainWindow.h" +#include "gui/ui_MenuEdgeContraction.h" + +#include "model/Model.h" + + +class Menu_edge_contraction : public QDialog,public Ui::MenuEdgeContraction{ + Q_OBJECT +private: + MainWindow* parent_; + const Model& model_; + + + void update_slider_value(); +public: + + Menu_edge_contraction(MainWindow* parent,const Model& model); + + void connectActions(MainWindow* parent); + + +private: + unsigned num_vertices(); + unsigned num_collapses(); + + public slots: + + void slider_value_changed(int new_slider_value); + void update_gui_numbers(); + void update_gui_numbers(int); + + void send_contract_edges(); + signals: + + void contract_edges(unsigned num_collapses); + +}; + + + +#endif /* MENU_EDGE_CONTRACTION_H_ */ diff --git a/src/GudhUI/gui/Menu_k_nearest_neighbors.cpp b/src/GudhUI/gui/Menu_k_nearest_neighbors.cpp new file mode 100644 index 00000000..21c67b2a --- /dev/null +++ b/src/GudhUI/gui/Menu_k_nearest_neighbors.cpp @@ -0,0 +1,55 @@ +/* + * Menu_k_nearest_neighbors.cpp + * + * Created on: Sep 11, 2014 + * Author: dsalinas + */ + + +#include "Menu_k_nearest_neighbors.h" + +Menu_k_nearest_neighbors::Menu_k_nearest_neighbors(QMainWindow* parent_): +parent(parent_) +{ + setupUi(this); + connectActions(parent_); +} + +void Menu_k_nearest_neighbors::connectActions(QMainWindow* parent){ + + QObject::connect( + this->pushButtonCompute, + SIGNAL(clicked()), + this, + SLOT(send_compute_k_nearest_neighbors()) + ); + QObject::connect( + this->spinBoxK, + SIGNAL(valueChanged(int)), + this, + SLOT(update_k(int)) + ); + QObject::connect( + this, + SIGNAL(compute_k_nearest_neighbors(unsigned)), + parent, + SLOT(build_k_nearest_neighbors(unsigned)) + ); + +} + +void Menu_k_nearest_neighbors::send_compute_k_nearest_neighbors(){ + emit(compute_k_nearest_neighbors((unsigned)spinBoxK->value())); +} + +void Menu_k_nearest_neighbors::accept(){ + send_compute_k_nearest_neighbors(); +} + +void Menu_k_nearest_neighbors::update_k(int new_k_value){ + if(checkBoxAutoUpdate->isChecked()) + emit(compute_k_nearest_neighbors((unsigned)spinBoxK->value())); +} + + +#include "Menu_k_nearest_neighbors.moc" diff --git a/src/GudhUI/gui/Menu_k_nearest_neighbors.h b/src/GudhUI/gui/Menu_k_nearest_neighbors.h new file mode 100644 index 00000000..d72b0074 --- /dev/null +++ b/src/GudhUI/gui/Menu_k_nearest_neighbors.h @@ -0,0 +1,39 @@ +/* + * Menu_k_nearest_neighbors.h + * + * Created on: Sep 11, 2014 + * Author: dsalinas + */ + +#ifndef MENU_K_NEAREST_NEIGHBORS_H_ +#define MENU_K_NEAREST_NEIGHBORS_H_ + +#include <QMainWindow> +#include "gui/ui_KNearestNeighborsMenu.h" + +class QWidget; + + +class Menu_k_nearest_neighbors : public QDialog,public Ui::KNearestNeighborsMenu{ + Q_OBJECT +private: + QMainWindow* parent; + +public: + + Menu_k_nearest_neighbors(QMainWindow* parent_); + + void connectActions(QMainWindow* parent); + + public slots: + void send_compute_k_nearest_neighbors(); + void update_k(int); + void accept(); + + signals: + void compute_k_nearest_neighbors(unsigned k); + +}; + + +#endif /* MENU_K_NEAREST_NEIGHBORS_H_ */ diff --git a/src/GudhUI/gui/Menu_persistence.cpp b/src/GudhUI/gui/Menu_persistence.cpp new file mode 100644 index 00000000..fae3a0e6 --- /dev/null +++ b/src/GudhUI/gui/Menu_persistence.cpp @@ -0,0 +1,60 @@ +/* + * Menu_persistence.cpp + * Created on: Jan 27, 2015 + * This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. + * + * Author(s): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Méditerranée (France) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + + +#include "Menu_persistence.h" + +Menu_persistence::Menu_persistence(QMainWindow* parent_):parent(parent_) +{ + setupUi(this); + connectActions(parent_); +} + +void Menu_persistence::connectActions(QMainWindow* parent){ + QObject::connect( + this, + SIGNAL(compute_persistence(int,double,int,double)), + parent, + SLOT(compute_persistence(int,double,int,double)) + ); +} + +void Menu_persistence::send_compute_persistence(){ + emit(compute_persistence(p_spinBox->value(),threshold_doubleSpinBox->value(), + maxdimension_spinBox->value(),minpersistence_doubleSpinBox->value())); +} + +void Menu_persistence::accept(){ + send_compute_persistence(); +} + +//void Menu_persistence::compute_persistence(int p_fied,double threshold,int dim_max,double min_persistence){ +//// if(checkBoxAutoUpdate->isChecked()) +//// emit(compute_k_nearest_neighbors((unsigned)spinBoxK->value())); +//} + + +#include "Menu_persistence.moc" diff --git a/src/GudhUI/gui/Menu_persistence.h b/src/GudhUI/gui/Menu_persistence.h new file mode 100644 index 00000000..67b64afa --- /dev/null +++ b/src/GudhUI/gui/Menu_persistence.h @@ -0,0 +1,59 @@ +/* + * Menu_persistence.h + * Created on: Jan 27, 2015 + * This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. + * + * Author(s): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Méditerranée (France) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + + +#ifndef MENU_PERSISTENCE_H_ +#define MENU_PERSISTENCE_H_ + + +#include <QMainWindow> +#include "gui/ui_PersistenceMenu.h" + +class QWidget; + + +class Menu_persistence : public QDialog,public Ui::PersistenceMenu{ + Q_OBJECT +private: + QMainWindow* parent; + +public: + + Menu_persistence(QMainWindow* parent_); + + void connectActions(QMainWindow* parent); + + public slots: + void send_compute_persistence(); + void accept(); + signals: + void compute_persistence(int p_fied,double threshold,int dim_max,double min_persistence); + +}; + + + +#endif /* MENU_PERSISTENCE_H_ */ diff --git a/src/GudhUI/gui/Menu_uniform_neighbors.cpp b/src/GudhUI/gui/Menu_uniform_neighbors.cpp new file mode 100644 index 00000000..86e2593e --- /dev/null +++ b/src/GudhUI/gui/Menu_uniform_neighbors.cpp @@ -0,0 +1,59 @@ +/* + * Menu_uniform_neighbors.cpp + * + * Created on: Sep 11, 2014 + * Author: dsalinas + */ + + + + + +#include "Menu_uniform_neighbors.h" + +Menu_uniform_neighbors::Menu_uniform_neighbors(QMainWindow* parent_): +parent(parent_) +{ + setupUi(this); + connectActions(parent_); +} + +void Menu_uniform_neighbors::connectActions(QMainWindow* parent){ + + QObject::connect( + this->pushButtonCompute, + SIGNAL(clicked()), + this, + SLOT(send_compute_uniform_neighbors()) + ); + QObject::connect( + this->doubleSpinBoxAlpha, + SIGNAL(valueChanged(double)), + this, + SLOT(update_alpha(double)) + ); + QObject::connect( + this, + SIGNAL(compute_uniform_neighbors(double)), + parent, + SLOT(build_rips(double)) + ); + +} + +void Menu_uniform_neighbors::send_compute_uniform_neighbors(){ + emit(compute_uniform_neighbors(doubleSpinBoxAlpha->value())); +} + +void Menu_uniform_neighbors::accept(){ + send_compute_uniform_neighbors(); +} + +void Menu_uniform_neighbors::update_alpha(double alpha){ + if(checkBoxAutoUpdate->isChecked()) + emit(compute_uniform_neighbors(doubleSpinBoxAlpha->value())); +} + + + +#include "Menu_uniform_neighbors.moc" diff --git a/src/GudhUI/gui/Menu_uniform_neighbors.h b/src/GudhUI/gui/Menu_uniform_neighbors.h new file mode 100644 index 00000000..cb90cc88 --- /dev/null +++ b/src/GudhUI/gui/Menu_uniform_neighbors.h @@ -0,0 +1,36 @@ +/* + * Menu_uniform_neighbors.h + * + * Created on: Sep 11, 2014 + * Author: dsalinas + */ + +#ifndef MENU_UNIFORM_NEIGHBORS_H_ +#define MENU_UNIFORM_NEIGHBORS_H_ + +#include <QMainWindow> +#include "gui/ui_UniformNeighborsMenu.h" + +class Menu_uniform_neighbors : public QDialog,public Ui::UniformMenu { + Q_OBJECT +private: + QMainWindow* parent; + +public: + + Menu_uniform_neighbors(QMainWindow* parent_); + + void connectActions(QMainWindow* parent); + + public slots: + void send_compute_uniform_neighbors(); + void update_alpha(double); + void accept(); + + signals: + void compute_uniform_neighbors(double alpha); + +}; + + +#endif /* MENU_UNIFORM_NEIGHBORS_H_ */ diff --git a/src/GudhUI/gui/PersistenceMenu.ui b/src/GudhUI/gui/PersistenceMenu.ui new file mode 100644 index 00000000..29327db2 --- /dev/null +++ b/src/GudhUI/gui/PersistenceMenu.ui @@ -0,0 +1,139 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>PersistenceMenu</class> + <widget class="QDialog" name="PersistenceMenu"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>354</width> + <height>275</height> + </rect> + </property> + <property name="windowTitle"> + <string>Point cloud persistence</string> + </property> + <widget class="QWidget" name=""> + <property name="geometry"> + <rect> + <x>20</x> + <y>23</y> + <width>318</width> + <height>226</height> + </rect> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QSpinBox" name="p_spinBox"> + <property name="minimum"> + <number>2</number> + </property> + <property name="value"> + <number>2</number> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Coefficient Z/pZ</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QSpinBox" name="maxdimension_spinBox"> + <property name="maximum"> + <number>9999</number> + </property> + <property name="value"> + <number>10</number> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>Max dimension</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QDoubleSpinBox" name="threshold_doubleSpinBox"> + <property name="maximum"> + <double>9999.000000000000000</double> + </property> + <property name="value"> + <double>1.000000000000000</double> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Max Rips offset</string> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QDoubleSpinBox" name="minpersistence_doubleSpinBox"/> + </item> + <item row="3" column="1"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Minimum Persistence</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>PersistenceMenu</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>PersistenceMenu</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/src/GudhUI/gui/UniformNeighborsMenu.ui b/src/GudhUI/gui/UniformNeighborsMenu.ui new file mode 100644 index 00000000..1f7cf980 --- /dev/null +++ b/src/GudhUI/gui/UniformNeighborsMenu.ui @@ -0,0 +1,150 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>UniformMenu</class> + <widget class="QDialog" name="UniformMenu"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>292</width> + <height>209</height> + </rect> + </property> + <property name="windowTitle"> + <string>Uniform neighbors (Rips)</string> + </property> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="geometry"> + <rect> + <x>50</x> + <y>160</y> + <width>171</width> + <height>32</height> + </rect> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + <widget class="QWidget" name="formLayoutWidget"> + <property name="geometry"> + <rect> + <x>30</x> + <y>10</y> + <width>249</width> + <height>84</height> + </rect> + </property> + <layout class="QFormLayout" name="formLayout_2"> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::AllNonFixedFieldsGrow</enum> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>alpha</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Metric</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QComboBox" name="comboBoxMetric"> + <item> + <property name="text"> + <string>Ambient</string> + </property> + </item> + <item> + <property name="text"> + <string>Reduced Space</string> + </property> + </item> + </widget> + </item> + <item row="0" column="1"> + <widget class="QDoubleSpinBox" name="doubleSpinBoxAlpha"> + <property name="maximum"> + <double>100000000.000000000000000</double> + </property> + <property name="singleStep"> + <double>0.100000000000000</double> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="gridLayoutWidget"> + <property name="geometry"> + <rect> + <x>30</x> + <y>110</y> + <width>250</width> + <height>40</height> + </rect> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="1"> + <widget class="QPushButton" name="pushButtonCompute"> + <property name="text"> + <string>Compute</string> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QCheckBox" name="checkBoxAutoUpdate"> + <property name="text"> + <string>auto update</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>UniformMenu</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>UniformMenu</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/src/GudhUI/gui/Viewer.cpp b/src/GudhUI/gui/Viewer.cpp new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/GudhUI/gui/Viewer.cpp diff --git a/src/GudhUI/gui/Viewer_instructor.cpp b/src/GudhUI/gui/Viewer_instructor.cpp new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/GudhUI/gui/Viewer_instructor.cpp diff --git a/src/GudhUI/gui/gudhui.cpp b/src/GudhUI/gui/gudhui.cpp new file mode 100644 index 00000000..8d90270f --- /dev/null +++ b/src/GudhUI/gui/gudhui.cpp @@ -0,0 +1,17 @@ +#include "MainWindow.h"
+#include <QApplication>
+#include <CGAL/Qt/resources.h>
+
+
+int main(int argc, char** argv)
+{
+ QApplication application(argc,argv);
+ application.setOrganizationDomain("inria.fr");
+ application.setOrganizationName("INRIA");
+ application.setApplicationName("GudhUI");
+
+ MainWindow mw;
+ application.setQuitOnLastWindowClosed(false);
+ mw.show();
+ return application.exec();
+}
diff --git a/src/GudhUI/gui/main_window.ui b/src/GudhUI/gui/main_window.ui new file mode 100644 index 00000000..ac3caf41 --- /dev/null +++ b/src/GudhUI/gui/main_window.ui @@ -0,0 +1,231 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MainWindow</class> + <widget class="QMainWindow" name="MainWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>861</width> + <height>880</height> + </rect> + </property> + <property name="windowTitle"> + <string>GudhUI</string> + </property> + <property name="tabShape"> + <enum>QTabWidget::Rounded</enum> + </property> + <widget class="QWidget" name="centralwidget"> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="Viewer" name="viewer" native="true"> + <property name="autoFillBackground"> + <bool>false</bool> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <widget class="QMenuBar" name="menubar"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>861</width> + <height>34</height> + </rect> + </property> + <widget class="QMenu" name="menuFile"> + <property name="title"> + <string>File</string> + </property> + <addaction name="actionLoad_points"/> + <addaction name="actionLoad_complex"/> + <addaction name="actionSave_points"/> + <addaction name="actionSave_complex"/> + </widget> + <widget class="QMenu" name="menuPoints"> + <property name="title"> + <string>Points</string> + </property> + <addaction name="actionNoise"/> + </widget> + <widget class="QMenu" name="menuGraph"> + <property name="title"> + <string>Graph</string> + </property> + <addaction name="actionK_nearest_neighbors_graph"/> + <addaction name="actionUniform_proximity_graph"/> + <addaction name="actionShow_graph_stats"/> + </widget> + <widget class="QMenu" name="menuComplex"> + <property name="title"> + <string>Complex</string> + </property> + <addaction name="actionContract_edges"/> + <addaction name="actionCollapse_vertices"/> + <addaction name="actionCollapse_edges"/> + <addaction name="actionShow_complex_stats"/> + <addaction name="actionShow_complex_dimension"/> + </widget> + <widget class="QMenu" name="menuView"> + <property name="title"> + <string>View</string> + </property> + <addaction name="actionPoints"/> + <addaction name="actionEdges"/> + <addaction name="actionTriangles"/> + <addaction name="actionChange_projection"/> + </widget> + <widget class="QMenu" name="menuTopology"> + <property name="title"> + <string>Topology</string> + </property> + <addaction name="actionEuler_characteristic"/> + <addaction name="actionShow_homology_group"/> + <addaction name="actionPersistence"/> + </widget> + <addaction name="menuFile"/> + <addaction name="menuPoints"/> + <addaction name="menuGraph"/> + <addaction name="menuComplex"/> + <addaction name="menuTopology"/> + <addaction name="menuView"/> + </widget> + <widget class="QStatusBar" name="statusbar"/> + <action name="actionLoad_points"> + <property name="text"> + <string>Load points</string> + </property> + </action> + <action name="actionLoad_complex"> + <property name="text"> + <string>Load complex</string> + </property> + </action> + <action name="actionSave_points"> + <property name="text"> + <string>Save points</string> + </property> + </action> + <action name="actionSave_complex"> + <property name="text"> + <string>Save complex</string> + </property> + </action> + <action name="actionNoise"> + <property name="text"> + <string>Noise</string> + </property> + </action> + <action name="actionLloyd"> + <property name="text"> + <string>Lloyd</string> + </property> + </action> + <action name="actionUniform_proximity_graph"> + <property name="text"> + <string>Uniform proximity graph</string> + </property> + </action> + <action name="actionK_nearest_neighbors_graph"> + <property name="text"> + <string>k-nearest neighbors graph</string> + </property> + </action> + <action name="actionShow_graph_stats"> + <property name="text"> + <string>Show graph stats</string> + </property> + </action> + <action name="actionBuild_complex_from_graph"> + <property name="text"> + <string>Graph expansion</string> + </property> + </action> + <action name="actionBuild_Delaunay_from_points"> + <property name="text"> + <string>Delaunay from points</string> + </property> + </action> + <action name="actionContract_edges"> + <property name="text"> + <string>Contract edges</string> + </property> + </action> + <action name="actionCollapse_vertices"> + <property name="text"> + <string>Collapse vertices</string> + </property> + </action> + <action name="actionCollapse_edges"> + <property name="text"> + <string>Collapse edges</string> + </property> + </action> + <action name="actionPoints"> + <property name="text"> + <string>Points</string> + </property> + </action> + <action name="actionEdges"> + <property name="text"> + <string>Edges</string> + </property> + </action> + <action name="actionTriangles"> + <property name="text"> + <string>Triangles</string> + </property> + </action> + <action name="actionChange_projection"> + <property name="text"> + <string>Change projection</string> + </property> + </action> + <action name="actionShow_complex_stats"> + <property name="text"> + <string>Show complex stats</string> + </property> + </action> + <action name="actionShow_complex_dimension"> + <property name="text"> + <string>Show complex dimension</string> + </property> + </action> + <action name="actionShow_homology_group"> + <property name="text"> + <string>Homology groups</string> + </property> + </action> + <action name="actionPersistence"> + <property name="text"> + <string>Point cloud persistence</string> + </property> + </action> + <action name="actionEuler_characteristic"> + <property name="text"> + <string>Euler characteristic</string> + </property> + </action> + <action name="actionHomology_groups"> + <property name="text"> + <string>Homology groups</string> + </property> + </action> + </widget> + <customwidgets> + <customwidget> + <class>Viewer</class> + <extends>QWidget</extends> + <header>view/Viewer.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/src/GudhUI/model/Complex_typedefs.h b/src/GudhUI/model/Complex_typedefs.h new file mode 100644 index 00000000..b6404d62 --- /dev/null +++ b/src/GudhUI/model/Complex_typedefs.h @@ -0,0 +1,39 @@ +/* + * Complex_typedefs.h + * + * Created on: Aug 26, 2014 + * Author: dsalinas + */ + +#ifndef COMPLEX_TYPEDEFS_H_ +#define COMPLEX_TYPEDEFS_H_ + + + +#include "gudhi/Skeleton_blocker/Skeleton_blocker_simple_geometric_traits.h" +#include "gudhi/Skeleton_blocker_geometric_complex.h" + +#include <CGAL/Kernel_d/Point_d.h> + +#include <CGAL/Cartesian.h> +#include <CGAL/Cartesian_d.h> + + +struct Geometry_trait : public CGAL::Cartesian_d<double> { + typedef CGAL::Cartesian<double>::Point_3 Point_3; + typedef CGAL::Cartesian<double>::Vector_3 Vector_3; + typedef CGAL::Point_d<Cartesian_d<double>> Point; + typedef CGAL::Vector_d<Cartesian_d<double>> Vector; +}; + +typedef Geometry_trait::Point Point; + + +using namespace Gudhi; +using namespace Gudhi::skbl; + +typedef Skeleton_blocker_simple_geometric_traits<Geometry_trait> Complex_geometric_traits; +typedef Skeleton_blocker_geometric_complex< Complex_geometric_traits > Complex; + + +#endif /* COMPLEX_TYPEDEFS_H_ */ diff --git a/src/GudhUI/model/Model.h b/src/GudhUI/model/Model.h new file mode 100644 index 00000000..0d0f91e6 --- /dev/null +++ b/src/GudhUI/model/Model.h @@ -0,0 +1,291 @@ +/* + * Model.h + * + * Created on: Aug 25, 2014 + * Author: david + */ + +#ifndef MODEL_H_ +#define MODEL_H_ + +#include <fstream> +#include <limits> +#include "gudhi/Clock.h" +#include "utils/UI_utils.h" +#include "utils/Lloyd_builder.h" +#include "utils/Rips_builder.h" +#include "utils/K_nearest_builder.h" +#include "utils/Vertex_collapsor.h" +#include "utils/Edge_collapsor.h" +#include "utils/Edge_contractor.h" +#include "utils/Persistence_compute.h" + +#include "gudhi/Skeleton_blocker/Skeleton_blocker_simple_geometric_traits.h" +#include "gudhi/Skeleton_blocker_geometric_complex.h" + +#include "gudhi/Off_reader.h" + +#include "Complex_typedefs.h" + + +#include <CGAL/Euclidean_distance.h> + + +template<typename Complex> +class CGAL_geometric_flag_complex_wrapper{ + Complex& complex_; + typedef typename Complex::Vertex_handle Vertex_handle; + typedef typename Complex::Point Point; + + const bool load_only_points_; + +public: + CGAL_geometric_flag_complex_wrapper(Complex& complex,bool load_only_points = false): + complex_(complex), + load_only_points_(load_only_points){ + } + + void init(int dim,int num_vertices,int num_max_faces,int num_edges) const{ + } + + void point(const std::vector<double>& coords){ + Point p(coords.size(),coords.begin(),coords.end()); + complex_.add_vertex(p); + } + + void maximal_face(std::vector<int> vertices){ + if (!load_only_points_){ + for (int i = 0; i<vertices.size()-1 ; ++i) + for (int j = i+1; j<vertices.size()-1 ; ++j) + complex_.add_edge(Vertex_handle(vertices[i]),Vertex_handle(vertices[j])); + } + } + void done() const{} +}; + + +class Model{ + +public: + Complex complex_; + typedef typename Complex::Vertex_handle Vertex_handle; + typedef typename Complex::CVI CVI; + + + Model():complex_(){ + } + +public: + void off_file_open(const std::string& name_file){ + UIDBGMSG("load off file",name_file); + complex_.clear(); + CGAL_geometric_flag_complex_wrapper<Complex> read_wraper(complex_); + Gudhi::read_off(name_file,read_wraper); + } + + void off_points_open(const std::string& name_file){ + UIDBGMSG("load off points",name_file); + complex_.clear(); + CGAL_geometric_flag_complex_wrapper<Complex> read_wraper(complex_); + Gudhi::read_off(name_file,read_wraper); + } + + void off_file_save(const std::string& name_file){ + UIDBG("save off file"); + } + + void off_points_save(const std::string& name_file){ + UIDBG("save off off_points_save"); + } + + // point sets operations + void uniform_noise(double amplitude){ + UIDBG("unif noise"); + for (auto v : complex_.vertex_range()) + complex_.point(v) = add_uniform_noise(complex_.point(v),amplitude); + } + +private: + Point add_uniform_noise(const Point& point,double amplitude){ + std::vector<double> new_point(point.dimension()); + for(int i = 0 ; i < point.dimension();++i){ + new_point[i] = point[i] + (rand() % 2 - .5) * amplitude; + } + return Point(point.dimension(), new_point.begin(),new_point.end()); + } + +public: + + void lloyd(int num_iterations,int num_closest_neighbors){ + UIDBG("lloyd"); + Lloyd_builder<Complex> lloyd_builder(complex_,1); + } + + double squared_eucl_distance(const Point& p1,const Point& p2) const{ + return Geometry_trait::Squared_distance_d()(p1,p2); + } + + // complex operations from points + void build_rips(double alpha){ + UIDBG("build_rips"); + Rips_builder<Complex> rips_builder(complex_,alpha); + } + + void build_k_nearest_neighbors(unsigned k){ + UIDBG("build_k_nearest"); + complex_.keep_only_vertices(); + K_nearest_builder<Complex> k_nearest_builder(complex_,k); + } + + void build_delaunay(){ + UIDBG("build_delaunay"); + complex_.keep_only_vertices(); + } + + + + void contract_edges(unsigned num_contractions){ + Clock c; + Edge_contractor<Complex> contractor(complex_,num_contractions); + std::cout<<"Time to simplify: "<<c.num_seconds()<<"s"<<std::endl; + } + + + void collapse_vertices(unsigned num_collapses){ + + auto old_num_vertices = complex_.num_vertices(); + Vertex_collapsor<Complex> collapsor(complex_,complex_.num_vertices()); + UIDBGMSG("num vertices collapsed:",old_num_vertices - complex_.num_vertices()); + } + + void collapse_edges(unsigned num_collapses){ + Edge_collapsor<Complex> collapsor(complex_,complex_.num_edges()); + } + + + void show_graph_stats(){ + std::cout << "++++++ Graph stats +++++++"<< std::endl; + std::cout << "Num vertices : " << complex_.num_vertices()<<std::endl; + std::cout << "Num edges : " << complex_.num_edges()<<std::endl; + std::cout << "Num connected components : " << complex_.num_connected_components()<<std::endl; + std::cout << "Min/avg/max degree : " << min_degree()<<"/"<<avg_degree()<<"/"<<max_degree()<<std::endl; + std::cout << "Num connected components : " << complex_.num_connected_components()<<std::endl; + std::cout << "Num connected components : " << complex_.num_connected_components()<<std::endl; + std::cout << "+++++++++++++++++++++++++"<< std::endl; + } + +private: + int min_degree() const{ + int res = std::numeric_limits<int>::max(); + for(auto v : complex_.vertex_range()) + res= std::min(res,complex_.degree(v)); + return res; + } + + int max_degree() const{ + int res = 0; + for(auto v : complex_.vertex_range()) + res= std::max(res,complex_.degree(v)); + return res; + } + + int avg_degree() const{ + int res = 0; + for(auto v : complex_.vertex_range()) + res+= complex_.degree(v); + return res / complex_.num_vertices(); + } + +public: + + + + void show_complex_stats(){ + std::cout << "++++++ Mesh stats +++++++"<< std::endl; + std::cout << "Num vertices : " << complex_.num_vertices()<<std::endl; + std::cout << "Num edges : " << complex_.num_edges()<<std::endl; + std::cout << "Num connected components : " << complex_.num_connected_components()<<std::endl; + std::cout << "+++++++++++++++++++++++++"<< std::endl; + + } + + void show_complex_dimension(){ + unsigned num_simplices = 0; + int euler = 0; + int dimension = 0; + Clock clock; + for(const auto &s : complex_.simplex_range()){ + num_simplices++; + dimension = std::max(s.dimension(),dimension); + if(s.dimension()%2==0) + euler+=1; + else + euler-=1; + } + clock.end(); + std::cout << "++++++ Mesh dimension +++++++"<< std::endl; + std::cout << "Dimension : " << dimension<<std::endl; + std::cout << "Euler characteristic : " << euler<<std::endl; + std::cout << "Num simplices : " << num_simplices <<std::endl; + std::cout << "Total time: " << clock <<std::endl; + std::cout << "Time per simplex: " << clock.num_seconds()/num_simplices <<" s"<<std::endl; + std::cout << "+++++++++++++++++++++++++"<< std::endl; + } + + + void show_homology_group(){ + Clock clock; + run_chomp(); + clock.end(); + } + + void show_euler_characteristic(){ + unsigned num_simplices = 0; + int euler = 0; + int dimension = 0; + for(const auto &s : complex_.simplex_range()){ + num_simplices++; + dimension = std::max(s.dimension(),dimension); + if(s.dimension()%2==0) + euler+=1; + else + euler-=1; + } + std::cout << "Saw "<<num_simplices<<" simplices with maximum dimension " << dimension<<std::endl; + std::cout << "The euler characteristic is : " << euler<<std::endl; + } + + void show_persistence( int p,double threshold,int max_dim,double min_pers){ + Persistence_compute<Complex> persistence(complex_,std::cout,Persistence_params(p,threshold,max_dim,min_pers)); + } + + +private: + void run_chomp(){ + save_complex_in_file_for_chomp(); + system("../src/utils/homsimpl chomp.sim"); + } + + void save_complex_in_file_for_chomp(){ + std::ofstream file; + file.open("chomp.sim"); + for(const auto &s : complex_.simplex_range()){ + bool first = true; + file<<"("; + for(auto x : s){ + if(first) first = false; + else file<<","; + file << x; + } + file<<")\n"; + } + } +public: + + + unsigned num_vertices() const{ + return complex_.num_vertices(); + } +}; + +#endif /* MODEL_H_ */ diff --git a/src/GudhUI/todo.txt b/src/GudhUI/todo.txt new file mode 100644 index 00000000..19d99a77 --- /dev/null +++ b/src/GudhUI/todo.txt @@ -0,0 +1,22 @@ +-- general + +o bug avec kreanrest neighbors lorsqu on baisse k après contraction après collapse vertices + +o clarify visitor sk_bl + + + +-- ui + +x points dimension arbitraire +x contractions + + +x faire le lien MainWindow - Model + + + + +-- bug +x bug ordre contraction -> just that first vertex placement dont work great +x pb construction rips diff --git a/src/GudhUI/utils/Edge_collapsor.h b/src/GudhUI/utils/Edge_collapsor.h new file mode 100644 index 00000000..9cf880e0 --- /dev/null +++ b/src/GudhUI/utils/Edge_collapsor.h @@ -0,0 +1,84 @@ +/* + * Collapsor.h + * + * Created on: Sep 25, 2014 + * Author: dsalinas + */ + +#ifndef COLLAPSOR_H_ +#define COLLAPSOR_H_ + +#include <list> +#include "utils/Edge_contractor.h" + +/** + * Iteratively puts every vertex at the center of its neighbors + */ +template<typename SkBlComplex> class Edge_collapsor{ +private: + SkBlComplex& complex_; + unsigned num_collapses_; +public: + typedef typename SkBlComplex::Vertex_handle Vertex_handle; + typedef typename SkBlComplex::Edge_handle Edge_handle; + + /** + * @brief Modify complex to be the expansion of the k-nearest neighbor + * symetric graph. + */ + Edge_collapsor(SkBlComplex& complex,unsigned num_collapses): + complex_(complex),num_collapses_(num_collapses) + { + std::list<Edge_handle> edges; + edges.insert(edges.begin(),complex_.edge_range().begin(),complex_.edge_range().end()); + + edges.sort( + [&](Edge_handle e1,Edge_handle e2){ + return squared_edge_length(e1) < squared_edge_length(e2); + }); + + collapse_edges(edges); + + } + +private: + + + void collapse_edges(std::list<Edge_handle>& edges){ + while(!edges.empty() && num_collapses_--){ + Edge_handle current_edge = edges.front(); + edges.pop_front(); + if(is_link_reducible(current_edge)) + complex_.remove_edge(current_edge); + } + + } + + bool is_link_reducible(Edge_handle e){ + auto link = complex_.link(e); + + if(link.empty()) return false; + + if(link.is_cone()) return true; + + if(link.num_connected_components()>1) return false; + + Edge_contractor<Complex> contractor(link,link.num_vertices()-1); + + return (link.num_vertices()==1); + } + + + double squared_edge_length(Edge_handle e) const{ + return squared_eucl_distance(complex_.point(complex_.first_vertex(e)),complex_.point(complex_.second_vertex(e))); + } + + double squared_eucl_distance(const Point& p1,const Point& p2) const{ + return Geometry_trait::Squared_distance_d()(p1,p2); + } + +}; + + + +#endif /* COLLAPSOR_H_ */ diff --git a/src/GudhUI/utils/Edge_contractor.h b/src/GudhUI/utils/Edge_contractor.h new file mode 100644 index 00000000..c7a86e0b --- /dev/null +++ b/src/GudhUI/utils/Edge_contractor.h @@ -0,0 +1,68 @@ +/* + * Contractor.h + * + * Created on: Sep 25, 2014 + * Author: dsalinas + */ + +#ifndef EDGE_CONTRACTOR_H_ +#define EDGE_CONTRACTOR_H_ + + +#include "gudhi/Skeleton_blocker_contractor.h" + +#include "gudhi/Contraction/Edge_profile.h" +#include "gudhi/Contraction/policies/Cost_policy.h" + + +/** + * Iteratively puts every vertex at the center of its neighbors + */ +template<typename SkBlComplex> class Edge_contractor{ +private: + SkBlComplex& complex_; + unsigned num_contractions_; + + /** + * @brief return a cost corresponding to the squared length of the edge + */ + template< typename EdgeProfile> class Length_cost : public contraction::Cost_policy<EdgeProfile>{ + public: + typedef typename contraction::Cost_policy<EdgeProfile>::Cost_type Cost_type; + typedef typename EdgeProfile::Point Point; + Cost_type operator()(const EdgeProfile& profile, const boost::optional<Point>& placement) const override{ + Cost_type res; + if(!placement) return res; + return Geometry_trait::Squared_distance_d()(profile.p0(),profile.p1()); //not working?? + } + }; + + public: + typedef typename SkBlComplex::Vertex_handle Vertex_handle; + typedef typename SkBlComplex::Edge_handle Edge_handle; + + /** + * @brief Modify complex to be the expansion of the k-nearest neighbor + * symetric graph. + */ + Edge_contractor(SkBlComplex& complex,unsigned num_contractions): + complex_(complex),num_contractions_(num_contractions) + { + typedef typename contraction::Edge_profile<Complex> Profile; + num_contractions = (std::min)((int)num_contractions,(int)(complex_.num_vertices()-1)); + contraction::Skeleton_blocker_contractor<Complex> contractor( + complex_, + new Length_cost<contraction::Edge_profile<Complex>>(), + contraction::make_first_vertex_placement<Profile>(), + contraction::make_link_valid_contraction<Profile>(), + contraction::make_remove_popable_blockers_visitor<Profile>() + ); + contractor.contract_edges(num_contractions); + } + + +}; + + + +#endif /* EDGE_CONTRACTOR_H_ */ diff --git a/src/GudhUI/utils/Furthest_point_epsilon_net.h b/src/GudhUI/utils/Furthest_point_epsilon_net.h new file mode 100644 index 00000000..590b65c4 --- /dev/null +++ b/src/GudhUI/utils/Furthest_point_epsilon_net.h @@ -0,0 +1,134 @@ +/* + * Furthest_point_epsilon_net.h + * + * Created on: Sep 26, 2014 + * Author: dsalinas + */ + +#ifndef FURTHEST_POINT_EPSILON_NET_H_ +#define FURTHEST_POINT_EPSILON_NET_H_ + +#include "utils/UI_utils.h" +#include <vector> + +/** + * Computes an epsilon net with furthest point strategy. + */ +template<typename SkBlComplex> class Furthest_point_epsilon_net{ +private: + SkBlComplex& complex_; + typedef typename SkBlComplex::Vertex_handle Vertex_handle; + typedef typename SkBlComplex::Edge_handle Edge_handle; + + /** + * Let V be the set of vertices. + * Initially v0 is one arbitrarly vertex and the set V0 is {v0}. + * Then Vk is computed as follows. + * First we compute the vertex pk that is the furthest from Vk + * then Vk = Vk \cup pk. + * The radius of pk is its distance to Vk and its meeting vertex + * is the vertex of Vk for which this distance is achieved. + */ + struct Net_filtration_vertex{ + Vertex_handle vertex_handle; + Vertex_handle meeting_vertex; + double radius; + + + Net_filtration_vertex( + Vertex_handle vertex_handle_, + Vertex_handle meeting_vertex_, + double radius_): + vertex_handle(vertex_handle_),meeting_vertex(meeting_vertex_),radius(radius_) + {} + + bool operator<(const Net_filtration_vertex& other ) const{ + return radius < other.radius; + } + + }; + +public: + + + std::vector<Net_filtration_vertex> net_filtration_; + + /** + * @brief Modify complex to be the expansion of the k-nearest neighbor + * symetric graph. + */ + Furthest_point_epsilon_net(SkBlComplex& complex): + complex_(complex) + { + if(!complex.empty()){ + init_filtration(); + for(int k = 2; k < net_filtration_.size(); ++k){ + update_radius_value(k); + } + } + } + + //xxx does not work if complex not full + double radius(Vertex_handle v){ + return net_filtration_[v.vertex].radius; + } + + + + +private: + + void init_filtration(){ + Vertex_handle v0 = *(complex_.vertex_range().begin()); + net_filtration_.reserve(complex_.num_vertices()); + for(auto v : complex_.vertex_range()){ + if(v != v0) + net_filtration_.push_back( + Net_filtration_vertex(v, + Vertex_handle(-1), + squared_eucl_distance(v,v0)) + ); + } + net_filtration_.push_back(Net_filtration_vertex(v0,Vertex_handle(-1),1e10)); + auto n = net_filtration_.size(); + sort_filtration(n-1); + } + + void update_radius_value(int k){ + int n = net_filtration_.size(); + int index_to_update = n-k; + for(int i = 0; i< index_to_update; ++i){ + net_filtration_[i].radius = (std::min)(net_filtration_[i].radius , + squared_eucl_distance( + net_filtration_[i].vertex_handle, + net_filtration_[index_to_update].vertex_handle + ) + ); + } + sort_filtration(n-k); + } + + /** + * sort all i first elements. + */ + void sort_filtration(int i){ + std::sort(net_filtration_.begin(),net_filtration_.begin()+ i); + } + + double squared_eucl_distance(Vertex_handle v1,Vertex_handle v2) const{ + return std::sqrt(Geometry_trait::Squared_distance_d()( + complex_.point(v1),complex_.point(v2)) + ); + } + + void print_filtration() const{ + for(auto v : net_filtration_){ + std::cerr <<"v="<<v.vertex_handle<<"-> d="<<v.radius<<std::endl; + } + } + +}; + + + +#endif /* FURTHEST_POINT_EPSILON_NET_H_ */ diff --git a/src/GudhUI/utils/K_nearest_builder.h b/src/GudhUI/utils/K_nearest_builder.h new file mode 100644 index 00000000..4acc0fbf --- /dev/null +++ b/src/GudhUI/utils/K_nearest_builder.h @@ -0,0 +1,106 @@ +/* + * K_nearest_builder.h + * + * Created on: Sep 10, 2014 + * Author: dsalinas + */ + +#ifndef K_NEAREST_BUILDER_H_ +#define K_NEAREST_BUILDER_H_ + +#include <unordered_map> +#include <boost/iterator/iterator_facade.hpp> +#include <CGAL/Euclidean_distance.h> +#include <CGAL/Orthogonal_k_neighbor_search.h> +#include <CGAL/Search_traits_d.h> + +#include "utils/UI_utils.h" +#include "model/Complex_typedefs.h" + +template<typename SkBlComplex> class K_nearest_builder{ +private: + + //todo uggh no virtual delete operator in Point + // so do a composition asap + class Point_d_with_id : public Point{ + typedef Point Base; + public: + Complex::Vertex_handle vertex_handle; + Point_d_with_id(int d=0) : Point(d) {} +// Point_d_with_id(int d, const Origin &o) : Base(d,o) {} + + Point_d_with_id(int a, int b, int c = 1) : + Base(RT(a),RT(b),RT(c)) {} + Point_d_with_id(int a, int b, int c, int d) : + Base(RT(a),RT(b),RT(c),RT(d)) {} + + template <class InputIterator> + Point_d_with_id (int d, InputIterator first, InputIterator last) + : Base (d, first, last) {} + template <class InputIterator> + + Point_d_with_id(const Point_d_with_id &p) : Base(p) {} + Point_d_with_id(const Base& p) : Base(p) {} + Point_d_with_id(const Base& p,Complex::Vertex_handle v) : Base(p),vertex_handle(v) {} + + }; + + struct Kernel_with_id : public Geometry_trait{ + typedef Point_d_with_id Point_d; + }; + + + /** + * TODO wrap vertex handle in class passed to tree + */ + typedef Kernel_with_id K; + typedef typename K::Point_d Point_d; + typedef typename CGAL::Search_traits_d<K> TreeTraits; + typedef typename CGAL::Orthogonal_k_neighbor_search<TreeTraits> Neighbor_search; + typedef typename Neighbor_search::Tree Tree; + + SkBlComplex& complex_; +public: + + /** + * @brief Modify complex to be the expansion of the k-nearest neighbor + * symetric graph. + */ + K_nearest_builder(SkBlComplex& complex,unsigned k):complex_(complex){ + complex.keep_only_vertices(); + compute_edges(k); + } + +private: + + + + double squared_eucl_distance(const Point& p1,const Point& p2) const{ + return Geometry_trait::Squared_distance_d()(p1,p2); + } + + void compute_edges(unsigned k){ + + std::list<Point_d_with_id> points_with_id; + for(auto v: complex_.vertex_range()){ + Point_d_with_id point_v(complex_.point(v),v); + points_with_id.push_back(point_v); + } + + Tree tree(points_with_id.begin(),points_with_id.end()); + + + for (auto p : complex_.vertex_range()){ + Neighbor_search search(tree, complex_.point(p),k+1); + for(auto it = ++search.begin(); it != search.end(); ++it){ + auto q = it->first.vertex_handle; + if (p != q && complex_.contains_vertex(p) && complex_.contains_vertex(q)) + complex_.add_edge(p,q); + } + } + } + + +}; + +#endif /* K_NEAREST_BUILDER_H_ */ diff --git a/src/GudhUI/utils/Lloyd_builder.h b/src/GudhUI/utils/Lloyd_builder.h new file mode 100644 index 00000000..db2a7973 --- /dev/null +++ b/src/GudhUI/utils/Lloyd_builder.h @@ -0,0 +1,78 @@ +/* + * Lloyd.h + * + * Created on: Sep 25, 2014 + * Author: dsalinas + */ + +#ifndef LLOYD_H_ +#define LLOYD_H_ + + +#include <vector> + +/** + * Iteratively puts every vertex at the center of its neighbors + */ +template<typename SkBlComplex> class Lloyd_builder{ +private: + SkBlComplex& complex_; + int dim; +public: + typedef typename SkBlComplex::Vertex_handle Vertex_handle; + /** + * @brief Modify complex to be the expansion of the k-nearest neighbor + * symetric graph. + */ + Lloyd_builder(SkBlComplex& complex,unsigned num_iterations):complex_(complex),dim(-1){ + if(!complex_.empty()){ + dim = get_dimension(); + while(num_iterations--){ + std::list<Point> new_points; + for(auto v : complex.vertex_range()) + new_points.push_back(barycenter_neighbors(v)); + + auto new_points_it = new_points.begin(); + for(auto v : complex.vertex_range()) + complex_.point(v) = *(new_points_it++); + } + } + } + +private: + + int get_dimension(){ + assert(!complex_.empty()); + for(auto v : complex_.vertex_range()) + return complex_.point(v).dimension(); + return -1; + } + + Point barycenter_neighbors(Vertex_handle v) const{ + if(complex_.degree(v)==0) + return complex_.point(v); + + std::vector<double> res(dim,0); + unsigned num_points = 0; + for(auto nv : complex_.vertex_range(v)){ + ++num_points; + const Point& point = complex_.point(nv); + assert(point.dimension() == dim); + for(int i = 0; i < point.dimension() ; ++i) + res[i] += point[i]; + } + for(auto& x : res) + x/= num_points; + return Point(dim,res.begin(),res.end()); + } + + + + double squared_eucl_distance(const Point& p1,const Point& p2) const{ + return Geometry_trait::Squared_distance_d()(p1,p2); + } + +}; + + +#endif /* LLOYD_H_ */ diff --git a/src/GudhUI/utils/MClock.h b/src/GudhUI/utils/MClock.h new file mode 100644 index 00000000..b5c7d191 --- /dev/null +++ b/src/GudhUI/utils/MClock.h @@ -0,0 +1,57 @@ +/* + * Clock.h + * + * Created on: Jun 17, 2014 + * Author: dsalinas + */ + +#ifndef CLOCK_H_ +#define CLOCK_H_ + +#include <sys/time.h> + + +class MClock{ + +public: + MClock(){ + end_called = false; + begin(); + } + + void begin() const{ + end_called = false; + gettimeofday(&startTime, NULL); + } + + void end() const{ + end_called = true; + gettimeofday(&endTime, NULL); + } + + friend std::ostream& operator<< (std::ostream& stream,const MClock& clock){ + // if(!clock.end_called) clock.end(); + if(!clock.end_called) stream << "end not called"; + else{ + long totalTime = (clock.endTime.tv_sec - clock.startTime.tv_sec) * 1000000L; + totalTime += (clock.endTime.tv_usec - clock.startTime.tv_usec); + stream << clock.num_seconds() <<"s"; + } + return stream; + + } + + double num_seconds() const{ + if(!end_called) end(); + long totalTime = (endTime.tv_sec - startTime.tv_sec) * 1000000L; + totalTime += (endTime.tv_usec - startTime.tv_usec); + return (totalTime / 1000L)/(double) 1000; + } + +private: + mutable struct timeval startTime, endTime; + mutable bool end_called; +}; + + +#endif /* CLOCK_H_ */ diff --git a/src/GudhUI/utils/Persistence_compute.h b/src/GudhUI/utils/Persistence_compute.h new file mode 100644 index 00000000..f7974287 --- /dev/null +++ b/src/GudhUI/utils/Persistence_compute.h @@ -0,0 +1,106 @@ +/* + * Persistence_compute.h + * Created on: Jan 26, 2015 + * This file is part of the Gudhi Library. The Gudhi library + * (Geometric Understanding in Higher Dimensions) is a generic C++ + * library for computational topology. + * + * Author(s): David Salinas + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Méditerranée (France) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + + +#ifndef PERSISTENCE_COMPUTE_H_ +#define PERSISTENCE_COMPUTE_H_ + + +#include "gudhi/graph_simplicial_complex.h" +#include "gudhi/Simplex_tree.h" +#include "gudhi/distance_functions.h" +#include "gudhi/Persistent_cohomology.h" +#include "gudhi/Persistent_cohomology/Multi_field.h" + + +struct Persistence_params{ + int p; + double threshold; + int max_dim; + double min_pers; + + Persistence_params(int p_,double th_,int max_dim_=10,double min_pers_=0) + :p(p_),threshold(th_),max_dim(max_dim_),min_pers(min_pers_){} +}; + + +/** + * Show persistence into output stream + */ +template<typename SkBlComplex> class Persistence_compute{ +private: + SkBlComplex& complex_; + std::ostream& stream_; +public: + typedef typename SkBlComplex::Vertex_handle Vertex_handle; + typedef typename SkBlComplex::Edge_handle Edge_handle; + + /** + * @brief Compute persistence + * parameters : + * unsigned dim_max + * double threshold + * int p for Z_p + */ + Persistence_compute(SkBlComplex& complex,std::ostream& stream,const Persistence_params& params): +// +// double threshold = 0.5,unsigned dim_max = 8): + complex_(complex),stream_(stream){ + + //for now everything is copied, todo boost adapt iterators to points of SkBlComplex instead of copying to an intial vector + typedef std::vector<double> Point_t; + std::vector< Point_t > points; + points.reserve(complex.num_vertices()); + for(auto v : complex.vertex_range()){ + const auto & pt = complex.point(v); + Point_t pt_to_add(pt.cartesian_begin(),pt.cartesian_end()); + points.emplace_back(std::move(pt_to_add)); + } + + + Graph_t prox_graph = compute_proximity_graph( points, params.threshold, euclidean_distance<Point_t> ); + Gudhi::Simplex_tree<> st; + st.insert_graph(prox_graph); + st.expansion( params.max_dim ); + + Gudhi::persistent_cohomology::Persistent_cohomology< Gudhi::Simplex_tree<>,Gudhi::persistent_cohomology::Field_Zp > pcoh (st); + pcoh.init_coefficients( params.p ); //initilizes the coefficient field for homology + pcoh.compute_persistent_cohomology( INFINITY ); //put params.min_persistence + stream_<<"persistence: \n"; + pcoh.output_diagram(stream_); + } + +private: + + +}; + + + + + + +#endif /* PERSISTENCE_COMPUTE_H_ */ diff --git a/src/GudhUI/utils/Rips_builder.h b/src/GudhUI/utils/Rips_builder.h new file mode 100644 index 00000000..9484f9ab --- /dev/null +++ b/src/GudhUI/utils/Rips_builder.h @@ -0,0 +1,56 @@ +/* + * Rips_builder.h + * + * Created on: Sep 10, 2014 + * Author: dsalinas + */ + +#ifndef RIPS_BUILDER_H_ +#define RIPS_BUILDER_H_ + +#include <boost/iterator/iterator_facade.hpp> + +#include "utils/UI_utils.h" +#include "model/Complex_typedefs.h" +#include <CGAL/Euclidean_distance.h> + +#include <CGAL/Orthogonal_k_neighbor_search.h> +#include <CGAL/Search_traits_d.h> + +template<typename SkBlComplex> class Rips_builder{ +private: + SkBlComplex& complex_; +public: + + /** + * @brief Modify complex to be the Rips complex + * of its points with offset alpha. + */ + Rips_builder(SkBlComplex& complex,double alpha):complex_(complex){ + complex.keep_only_vertices(); + if (alpha<=0) return; + compute_edges(alpha); + } + +private: + + + double squared_eucl_distance(const Point& p1,const Point& p2) const{ + return Geometry_trait::Squared_distance_d()(p1,p2); + } + + void compute_edges(double alpha){ + auto vertices = complex_.vertex_range(); + for(auto p = vertices.begin(); p!= vertices.end(); ++p){ + std::cout << *p << " "; std::cout.flush(); + for (auto q = p; ++q != vertices.end(); /**/) + if (squared_eucl_distance(complex_.point(*p),complex_.point(*q)) < 4*alpha*alpha) + complex_.add_edge(*p,*q); + } + std::cout << std::endl; + } + +}; + + +#endif /* RIPS_BUILDER_H_ */ diff --git a/src/GudhUI/utils/UI_utils.h b/src/GudhUI/utils/UI_utils.h new file mode 100644 index 00000000..a7c0689f --- /dev/null +++ b/src/GudhUI/utils/UI_utils.h @@ -0,0 +1,33 @@ +/* + * UI_utils.h + * + * Created on: Aug 25, 2014 + * Author: david + */ + +#ifndef UI_UTILS_H_ +#define UI_UTILS_H_ + +#define PRINT(a) std::cerr << #a << ": " << (a) << " (DISP)"<<std::endl + +#define UIDBG_VERBOSE + + +#ifdef UIDBG_VERBOSE +#define UIDBG(a) std::cerr << "UIDBG: " << (a)<<std::endl +#define UIDBGMSG(a,b) std::cerr << "UIDBG: " << a<<b<<std::endl +#define UIDBGVALUE(a) std::cerr << "UIDBG: " << #a << ": " << a<<std::endl +#define UIDBGCONT(a) std::cerr << "UIDBG: container "<< #a<<" -> "; for(auto x:a) std::cerr<< x << ","; std::cerr<<std::endl +#else +//#define DBG(a) a +//#define DBGMSG(a,b) b +//#define DBGVALUE(a) a +//#define DBGCONT(a) a +#define UIDBG(a) +#define UIDBGMSG(a,b) +#define UIDBGVALUE(a) +#define UIDBGCONT(a) +#endif + + +#endif /* UI_UTILS_H_ */ diff --git a/src/GudhUI/utils/Vertex_collapsor.h b/src/GudhUI/utils/Vertex_collapsor.h new file mode 100644 index 00000000..d4911a35 --- /dev/null +++ b/src/GudhUI/utils/Vertex_collapsor.h @@ -0,0 +1,76 @@ +/* + * Vertex_collapsor.h + * + * Created on: Sep 25, 2014 + * Author: dsalinas + */ + +#ifndef VERTEX_COLLAPSOR_H_ +#define VERTEX_COLLAPSOR_H_ + +#include "utils/Edge_contractor.h" +#include "utils/Furthest_point_epsilon_net.h" +#include "utils/UI_utils.h" +/** + * Iteratively puts every vertex at the center of its neighbors + */ +template<typename SkBlComplex> class Vertex_collapsor{ +private: + SkBlComplex& complex_; + size_t num_collapses_; +public: + typedef typename SkBlComplex::Vertex_handle Vertex_handle; + typedef typename SkBlComplex::Edge_handle Edge_handle; + + /** + * @brief Modify complex to be the expansion of the k-nearest neighbor + * symetric graph. + */ + Vertex_collapsor(SkBlComplex& complex, size_t num_collapses) : + complex_(complex),num_collapses_(num_collapses) + { +// std::list<Vertex_handle> vertices; +// vertices.insert(vertices.begin(),complex_.vertex_range().begin(),complex_.vertex_range().end()); +// UIDBG("Collapse vertices"); +// collapse_vertices(vertices); + + std::list<Vertex_handle> vertices; + + UIDBG("Compute eps net"); + Furthest_point_epsilon_net<Complex> eps_net(complex_); + + for(auto vh : eps_net.net_filtration_) + vertices.push_back(vh.vertex_handle); + + UIDBG("Collapse vertices"); + collapse_vertices(vertices); + + + + } + +private: + + + void collapse_vertices(std::list<Vertex_handle>& vertices){ + while(!vertices.empty() && num_collapses_--){ + Vertex_handle current_vertex = vertices.front(); + vertices.pop_front(); + if(is_link_reducible(current_vertex)) + complex_.remove_vertex(current_vertex); + } + } + + bool is_link_reducible(Vertex_handle v){ + auto link = complex_.link(v); + if(link.empty()) return false; + if(link.is_cone()) return true; + if(link.num_connected_components()>1) return false; + Edge_contractor<Complex> contractor(link,link.num_vertices()-1); + return (link.num_vertices()==1); + } + +}; + + +#endif /* VERTEX_COLLAPSOR_H_ */ diff --git a/src/GudhUI/utils/homsimpl b/src/GudhUI/utils/homsimpl Binary files differnew file mode 100755 index 00000000..12227502 --- /dev/null +++ b/src/GudhUI/utils/homsimpl diff --git a/src/GudhUI/view/Color.h b/src/GudhUI/view/Color.h new file mode 100644 index 00000000..a63456cb --- /dev/null +++ b/src/GudhUI/view/Color.h @@ -0,0 +1,21 @@ +/* + * Color.h + * + * Created on: Aug 26, 2014 + * Author: dsalinas + */ + +#ifndef COLOR_H_ +#define COLOR_H_ + + + +struct Color{ + double r; + double g; + double b; + Color(double r_,double g_,double b_):r(r_),g(g_),b(b_){} +}; + + +#endif /* COLOR_H_ */ diff --git a/src/GudhUI/view/FirstCoordProjector.h b/src/GudhUI/view/FirstCoordProjector.h new file mode 100644 index 00000000..2659eef1 --- /dev/null +++ b/src/GudhUI/view/FirstCoordProjector.h @@ -0,0 +1,24 @@ +/* + * FirstCoordProjector.h + * + * Created on: Aug 27, 2014 + * Author: dsalinas + */ + +#ifndef FIRSTCOORDPROJECTOR_H_ +#define FIRSTCOORDPROJECTOR_H_ + +#include "utils/UI_utils.h" +#include "Projector3D.h" + +class FirstCoordProjector3D : public Projector3D{ + typedef Projector3D::Point Point; + typedef Projector3D::Point_3 Point_3; + + Point_3 operator()(const Point& p) const{ + assert(p.dimension()>=3); + return Point_3(p.x(),p.y(),p.z()); + } +}; + +#endif /* FIRSTCOORDPROJECTOR_H_ */ diff --git a/src/GudhUI/view/Projector3D.h b/src/GudhUI/view/Projector3D.h new file mode 100644 index 00000000..503b35c5 --- /dev/null +++ b/src/GudhUI/view/Projector3D.h @@ -0,0 +1,28 @@ +/* + * Projector.h + * + * Created on: Aug 27, 2014 + * Author: dsalinas + */ + +#ifndef PROJECTOR3D_H_ +#define PROJECTOR3D_H_ + +#include "model/Complex_typedefs.h" + + +class Projector3D{ +public: + typedef Geometry_trait::Point Point; + typedef Geometry_trait::Point_3 Point_3; + + virtual Point_3 operator()(const Point&) const = 0; + + virtual ~Projector3D(){ + } + +}; + + + +#endif /* PROJECTOR3D_H_ */ diff --git a/src/GudhUI/view/View_parameter.h b/src/GudhUI/view/View_parameter.h new file mode 100644 index 00000000..39c5d7dd --- /dev/null +++ b/src/GudhUI/view/View_parameter.h @@ -0,0 +1,137 @@ +/* + * View_parameter.h + * + * Created on: Mar 10, 2014 + * Author: David Salinas + * Copyright 2013 INRIA. All rights reserved + */ + +#ifndef VIEW_PARAMETER_H_ +#define VIEW_PARAMETER_H_ + +#include <iostream> + +/** + * Different parameters for the view such as the camera angle, + * the light, options for vertices/edges/triangles. + */ +class View_parameter{ +public: + bool light; + bool relative_light; + + double size_vertices; + double size_edges; + double light_edges; // in 0-1 + double light_triangles;// in 0-1 + + /** + * light angle + */ + double theta; + double phi; + + enum VERTEX_MODE{ V_NONE,V_SIMPLE,V_COUNT}; + enum EDGE_MODE{ E_NONE,E_SIMPLE,E_COUNT}; + enum TRIANGLE_MODE{ T_NONE,T_SIMPLE,T_COUNT}; + + + + + VERTEX_MODE vertex_mode; + EDGE_MODE edge_mode; + TRIANGLE_MODE triangle_mode; + + void change_vertex_mode(){ + int current_value = vertex_mode; + vertex_mode = static_cast<VERTEX_MODE>(++current_value % V_COUNT); + std::cout<<"Vertex mode : "; + switch (vertex_mode) { + case V_NONE: + std::cout<<"empty\n"; + break; + case V_SIMPLE: + std::cout<<"simple\n"; + break; + default: + break; + } + } + + void change_vertex_mode(int new_mode){ + vertex_mode = static_cast<VERTEX_MODE>(new_mode % V_COUNT); + } + + void change_edge_mode(){ + int current_value = edge_mode; + edge_mode = static_cast<EDGE_MODE>(++current_value % E_COUNT); + } + + void change_edge_mode(int new_mode){ + edge_mode = static_cast<EDGE_MODE>(new_mode % E_COUNT); + } + + + void change_triangle_mode(){ + int current_value = triangle_mode; + triangle_mode = static_cast<TRIANGLE_MODE>(++current_value % T_COUNT); + } + + + + + + View_parameter(){ + light = true; + relative_light = true; + vertex_mode = V_SIMPLE; + edge_mode = E_SIMPLE; + triangle_mode = T_NONE; + + size_vertices = 3; + size_edges = 2; + + light_edges = 0.3; + light_triangles = 0.85; + theta = 0; + phi = 0; + } + + friend std::ostream& operator<<(std::ostream& stream, const View_parameter& param){ + stream << param.light<< " "; + stream << param.relative_light<< " "; + stream << param.vertex_mode<< " "; + stream << param.edge_mode<< " "; + stream << param.triangle_mode<< " "; + stream << param.size_vertices<< " "; + stream << param.size_edges<< " "; + stream << param.light_edges<< " "; + stream << param.light_triangles<< " "; + stream << param.theta<< " "; + stream << param.phi<< " "; + return stream; + } + + friend std::istream& operator>>(std::istream& stream, View_parameter& param){ + stream >> param.light; + stream >> param.relative_light; + int a; + stream>>a; + param.vertex_mode = static_cast<VERTEX_MODE>(a % V_COUNT); + stream>>a; + param.edge_mode = static_cast<EDGE_MODE>(a % E_COUNT); + stream>>a; + param.triangle_mode = static_cast<TRIANGLE_MODE>(a % T_COUNT); + stream>>a; + stream >> param.size_vertices; + stream >> param.size_edges; + stream >> param.light_edges; + stream >> param.light_triangles; + stream >> param.theta; + stream >> param.phi; + return stream; + } + +}; + +#endif /* VIEW_PARAMETER_H_ */ diff --git a/src/GudhUI/view/Viewer.cpp b/src/GudhUI/view/Viewer.cpp new file mode 100644 index 00000000..d8a35faf --- /dev/null +++ b/src/GudhUI/view/Viewer.cpp @@ -0,0 +1,197 @@ +/* + * Viewer.cpp + * + * Created on: Aug 26, 2014 + * Author: dsalinas + */ + +#include "Viewer.h" +#include "utils/UI_utils.h" + +Viewer::Viewer(QWidget* parent): QGLViewer(QGLFormat(QGL::SampleBuffers),parent),instructor(0),theta(0),phi(0){ +} + +void +Viewer::set_instructor(Viewer_instructor* instructor_){ + instructor = instructor_; +} + +void +Viewer::show_entire_scene(){ + this->showEntireScene(); +} + +void +Viewer::draw(){ + instructor->give_instructions(); +} + + +void +Viewer::set_bounding_box(const Point_3 & lower_left,const Point_3 & upper_right){ + this->camera()->setSceneBoundingBox( + qglviewer::Vec(lower_left[0], lower_left[1], lower_left[2]), + qglviewer::Vec(upper_right[0], upper_right[1], upper_right[2]) + ); +} + +void +Viewer::update_GL(){ + this->updateGL(); + +} + +void +Viewer::init_scene(){ + this->setBackgroundColor(Qt::white); + ::glEnable(GL_LINE_SMOOTH); + init_light(); +} + +void +Viewer::init_light(){ + ::glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); +} + +void +Viewer::set_light(){ + if(theta>=0 && phi >=0){ + const GLfloat pos[4] = {(float)(sin(phi)*cos(theta)),(float)(sin(phi)*sin(theta)),(float)(cos(phi)),0.}; + glLightfv(GL_LIGHT0, GL_POSITION, pos); + } +} + +void +Viewer::set_light_direction(double theta_,double phi_){ + theta = theta_; + phi = phi_; +} + +/** + * set the light in the direction of the observer + */ +void +Viewer::set_light_direction(){ + theta = -1; + phi = -1; +} + + +void +Viewer::postSelection(const QPoint& point){ + bool found; + + auto vec = this->camera()->pointUnderPixel(point,found); + + if(found){ + Point_3 position(vec[0],vec[1],vec[2]); + emit(click(position)); + } +} + +//////////////////////// +// draw +//////////////////////// +void +Viewer::set_size_point(double size_points){ + ::glPointSize(size_points); +} + +void +Viewer::draw_point(const Point_3& p,const Color& color,double size_points){ + ::glColor3f(color.r,color.g,color.b); + ::glDisable(GL_LIGHTING); + ::glEnable(GL_POINT_SMOOTH); + ::glPointSize(size_points); + ::glBegin(GL_POINTS); + ::glVertex3d(p.x(), p.y(), p.z()); + ::glEnd(); + ::glDisable(GL_POINT_SMOOTH); +} + +void +Viewer::begin_draw_points(double size,bool light){ + light?glEnable(GL_LIGHTING):glDisable(GL_LIGHTING); + ::glEnable(GL_POINT_SMOOTH); + ::glPointSize(size); + ::glBegin(GL_POINTS); +} + +void +Viewer::set_color(const Color& color){ + ::glColor3f(color.r,color.g,color.b); +} + +void +Viewer::draw_points(const Point_3 & point){ + ::glVertex3d(point.x(),point.y(),point.z()); +} + +void +Viewer::end_draw_points(){ + ::glEnd(); + ::glDisable(GL_POINT_SMOOTH); +} + +void +Viewer::draw_edge(const Point_3 &a,const Point_3 &b,const Color& color,double size){ + ::glColor3f(color.r,color.g,color.b); + ::glPointSize(3.0); + ::glLineWidth(size); + ::glBegin(GL_LINES); + ::glVertex3f(a.x(),a.y(),a.z()); + ::glVertex3f(b.x(),b.y(),b.z()); + ::glEnd(); +} + +void +Viewer::begin_draw_edges(double size,bool light){ + ::glLineWidth(size); + ::glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); + ::glEnable(GL_POLYGON_OFFSET_LINE); + ::glPolygonOffset(3.0f,-3.0f); + light?glEnable(GL_LIGHTING):glDisable(GL_LIGHTING); + ::glBegin(GL_LINES); +} + +void +Viewer::draw_edges(const Point_3 &a,const Point_3 &b){ + ::glVertex3f(a.x(),a.y(),a.z()); + ::glVertex3f(b.x(),b.y(),b.z()); +} + +void +Viewer::end_draw_edges(){ + ::glEnd(); +} + +void +Viewer::begin_draw_triangles(double size,bool light,bool transparent){ + if(transparent){ + ::glEnable (GL_BLEND); + ::glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + ::glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); + ::glEnable(GL_POLYGON_OFFSET_FILL); + ::glPolygonOffset(3.0f,-3.0f); + light?glEnable(GL_LIGHTING):glDisable(GL_LIGHTING); + ::glBegin(GL_TRIANGLES); +} + +void +Viewer::draw_triangles(const Point_3& p1,const Point_3& p2,const Point_3& p3){ + if(!CGAL::collinear(p1,p2,p3)){ + auto triangle_normal = CGAL::unit_normal(p1,p2,p3); + ::glNormal3d(triangle_normal.x(),triangle_normal.y(),triangle_normal.z()); + ::glVertex3d(p1.x(),p1.y(),p1.z()); + ::glVertex3d(p2.x(),p2.y(),p2.z()); + ::glVertex3d(p3.x(),p3.y(),p3.z()); + } +} + +void +Viewer::end_draw_triangles(){ + ::glEnd(); +} + +#include "Viewer.moc" diff --git a/src/GudhUI/view/Viewer.h b/src/GudhUI/view/Viewer.h new file mode 100755 index 00000000..5639aa56 --- /dev/null +++ b/src/GudhUI/view/Viewer.h @@ -0,0 +1,96 @@ +#ifndef VIEWER_H
+#define VIEWER_H
+
+#include <QGLViewer/qglviewer.h>
+#include "View_parameter.h"
+#include "model/Complex_typedefs.h"
+#include "Color.h"
+#include "Viewer_instructor.h"
+
+class Viewer_instructor;
+
+class Viewer : public QGLViewer {
+ Q_OBJECT
+
+ Viewer_instructor * instructor;
+
+ /**
+ * light angles
+ */
+ double theta,phi;
+ typedef Complex::GT Gudhi_kernel;
+ typedef Gudhi_kernel::Point_3 Point_3;
+public:
+ Viewer(QWidget* parent);
+
+ void set_instructor(Viewer_instructor* instructor_);
+
+ void show_entire_scene();
+
+ void draw();
+
+
+ void set_bounding_box(const Point_3 & lower_left,const Point_3 & upper_right);
+
+ void update_GL();
+
+ void init_scene();
+
+ void init_light();
+
+ void set_light();
+
+ void set_light_direction(double theta,double phi);
+
+ /**
+ * set the light in the direction of the observer
+ */
+ void set_light_direction();
+
+
+protected:
+ virtual void postSelection(const QPoint& point);
+
+
+public:
+
+ ////////////////////////
+ // draw
+ ////////////////////////
+ void set_size_point(double size_points);
+
+ void set_color(const Color& color);
+
+ void draw_point(const Point_3& p,const Color& color,double size_points);
+
+ void begin_draw_points(double size,bool light=false);
+
+ void draw_points(const Point_3 & point);
+
+ void end_draw_points();
+
+ void draw_edge(const Point_3 &a,const Point_3 &b,const Color& color,double size);
+
+ void begin_draw_edges(double size,bool light=false);
+
+ void draw_edges(const Point_3 &a,const Point_3 &b);
+
+ void end_draw_edges();
+
+ void begin_draw_triangles(double size,bool light,bool transparent = false);
+
+ void draw_triangles(const Point_3& p1,const Point_3& p2,const Point_3& p3);
+
+ //todo remove
+ void draw_triangles(const std::vector<Point_3*>& points);
+
+ void end_draw_triangles();
+
+
+ signals:
+ void click(const Point_3& position);
+};
+
+
+
+#endif
diff --git a/src/GudhUI/view/Viewer_instructor.cpp b/src/GudhUI/view/Viewer_instructor.cpp new file mode 100644 index 00000000..3cb8f152 --- /dev/null +++ b/src/GudhUI/view/Viewer_instructor.cpp @@ -0,0 +1,206 @@ +/* + * Viewer_instructor.cpp + * + * Created on: Aug 26, 2014 + * Author: dsalinas + */ + +#include <utility> +#include "Viewer_instructor.h" +#include "utils/UI_utils.h" +#include "FirstCoordProjector.h" + + +Viewer_instructor::Viewer_instructor(QWidget* parent, + Viewer* viewer, + const Complex& mesh +):viewer_(viewer),mesh_(mesh),projector_(new FirstCoordProjector3D()){ + viewer_->set_instructor(this); +} + + +void +Viewer_instructor::initialize_bounding_box(){ + auto pair_bounding_box = compute_bounding_box_corners(); + viewer_->set_bounding_box(proj(pair_bounding_box.first),proj(pair_bounding_box.second)); + viewer_->init_scene(); +} + +std::pair<Complex::Point,Complex::Point> +Viewer_instructor::compute_bounding_box_corners(){ + if(mesh_.empty()){ + return std::make_pair(Point(-1,-1,-1,1),Point(1,1,1,1)); + } + else{ + double x_min = 1e10; + double y_min = 1e10; + double z_min = 1e10; + double x_max = -1e10; + double y_max = -1e10; + double z_max = -1e10; + for( auto vi : mesh_.vertex_range()) + { + auto pt = proj(mesh_.point(vi)); + x_min = (std::min)(x_min,pt.x()); + y_min = (std::min)(y_min,pt.y()); + z_min = (std::min)(z_min,pt.z()); + + x_max = (std::max)(x_max,pt.x()); + y_max = (std::max)(y_max,pt.y()); + z_max = (std::max)(z_max,pt.z()); + + } + return std::make_pair( + Point(x_min,y_min,z_min,1.), + Point(x_max,y_max,z_max,1.) + ); + } +} + +void +Viewer_instructor::show_entire_scene(){ + viewer_->show_entire_scene(); +} + +const qglviewer::Camera* +Viewer_instructor::camera() const{ + return viewer_->camera(); +} + +int +Viewer_instructor::width() const{ + return viewer_->width(); +} +int +Viewer_instructor::height() const{ + return viewer_->height(); +} + +/** + * to change display parameters + */ +View_parameter& +Viewer_instructor::view_params(){ + return view_params_; +} + + +void +Viewer_instructor::give_instructions(){ + if(view_params_.relative_light) + viewer_->set_light_direction(); + else + viewer_->set_light_direction(view_params_.theta,view_params_.phi); + viewer_->set_light(); + + if (view_params_.edge_mode) draw_edges(); + if (view_params_.triangle_mode) draw_triangles(); + if (view_params_.vertex_mode) draw_points(); + +} + +void +Viewer_instructor::draw_edges(){ + viewer_->begin_draw_edges(view_params_.size_edges,false); + + for(auto edge : mesh_.edge_range()){ + set_color_edge(edge); + const Point& a = mesh_.point(mesh_.first_vertex(edge)); + const Point& b = mesh_.point(mesh_.second_vertex(edge)) ; + viewer_->draw_edges(proj(a),proj(b)); + } + + viewer_->end_draw_edges(); +} + +void +Viewer_instructor::draw_triangles(){ + const double size_triangles = 1.0; + viewer_->begin_draw_triangles(size_triangles,view_params_.light); + + for(const auto& fit : mesh_.triangle_range()) { + set_color_triangle(fit); + if(view_params_.triangle_mode){ + auto fit_it = fit.begin(); + const Point& p1 = mesh_.point(*fit_it); + const Point& p2 = mesh_.point(*(++fit_it)); + const Point& p3 = mesh_.point(*(++fit_it)); + viewer_->draw_triangles(proj(p1),proj(p2),proj(p3)); + } + } + viewer_->end_draw_triangles(); +} + +void +Viewer_instructor::draw_points(){ + viewer_->begin_draw_points( view_params_.size_vertices); + for( auto vi : mesh_.vertex_range()) + { + viewer_->set_size_point(view_params_.size_vertices); + set_color_vertex(vi); + viewer_->draw_points(proj(mesh_.point(vi))); + } + viewer_->end_draw_points(); +} + + +void +Viewer_instructor::draw_edge(const Point&,const Point&){ + +} + +void +Viewer_instructor::draw_point(const Point&){ + +} + + +/** + * set the right color of vertex/edge/triangle considering the view_params choice + */ +void +Viewer_instructor::set_color_vertex(Vertex_handle vh){ + viewer_->set_color(Color(view_params_.light_edges,view_params_.light_edges,view_params_.light_edges)); +} + +void +Viewer_instructor::set_color_edge(Edge_handle eh) { + viewer_->set_color(Color(view_params_.light_edges,view_params_.light_edges,view_params_.light_edges)); +} + +void +Viewer_instructor::set_color_triangle(const Simplex_handle& triangle){ + viewer_->set_color(Color(view_params_.light_triangles,view_params_.light_triangles,view_params_.light_triangles)); +} + + +Viewer_instructor::Point_3 +Viewer_instructor::proj(const Point& p) const{ + return (*projector_)(p); +} + + +void +Viewer_instructor::sceneChanged(){ + UIDBG("sceneChanged"); + viewer_->update_GL(); +} + +void +Viewer_instructor::change_draw_vertices(){ + view_params_.change_vertex_mode(); +} +void +Viewer_instructor::change_draw_edges(){ + view_params_.change_edge_mode(); +} +void +Viewer_instructor::change_draw_triangles(){ + view_params_.change_triangle_mode(); +} +void +Viewer_instructor::change_light(){ + view_params_.light =! view_params_.light ; +} + +#include "Viewer_instructor.moc" diff --git a/src/GudhUI/view/Viewer_instructor.h b/src/GudhUI/view/Viewer_instructor.h new file mode 100755 index 00000000..9a2a236b --- /dev/null +++ b/src/GudhUI/view/Viewer_instructor.h @@ -0,0 +1,108 @@ +#ifndef VIEWER_INSTRUCTOR_H
+#define VIEWER_INSTRUCTOR_H
+
+// todo do a viewer instructor that have directely a pointer to a QGLviewer and buffer ot not triangles
+
+
+#include <memory>
+
+#include <QFileDialog>
+#include <QKeyEvent>
+#include <QGLViewer/camera.h>
+
+
+#include "model/Complex_typedefs.h"
+
+#include "Projector3D.h"
+#include "View_parameter.h"
+#include "Viewer.h"
+
+class Viewer;
+class Viewer_parameter;
+
+class Viewer_instructor : public QWidget{
+ Q_OBJECT
+
+ typedef Geometry_trait::Point_3 Point_3;
+ typedef Complex::Point Point;
+ typedef Complex::Vertex_handle Vertex_handle;
+ typedef Complex::Edge_handle Edge_handle;
+ typedef Complex::Simplex_handle Simplex_handle;
+
+
+ Viewer* viewer_;
+ View_parameter view_params_;
+ const Complex& mesh_;
+ std::unique_ptr<Projector3D> projector_;
+
+
+public:
+
+ Viewer_instructor(QWidget* parent,
+ Viewer* viewer,
+ const Complex& mesh
+ );
+
+
+ void initialize_bounding_box();
+
+ std::pair<Point,Point> compute_bounding_box_corners();
+
+ void show_entire_scene();
+
+ const qglviewer::Camera* camera() const;
+
+ int width() const;
+ int height() const;
+
+ /**
+ * to change display parameters
+ */
+ View_parameter& view_params();
+
+
+public:
+
+ /**
+ * gives instructions to the viewer
+ */
+ void give_instructions();
+
+ void draw_edges();
+ void draw_triangles();
+ void draw_points();
+
+
+ void draw_edge(const Point&,const Point&);
+
+ void draw_point(const Point&);
+
+
+ /**
+ * set the right color of vertex/edge/triangle considering the view_params choice
+ */
+ void set_color_vertex(Vertex_handle vh);
+ void set_color_edge(Edge_handle eh);
+
+ void set_color_triangle(const Simplex_handle& triangle);
+
+private:
+ /**
+ * Projection to 3D needed for the viewer.
+ */
+ Point_3 proj(const Point& p) const;
+
+ public slots :
+
+ void sceneChanged();
+
+ void change_draw_vertices();
+ void change_draw_edges();
+ void change_draw_triangles();
+ void change_light();
+
+
+
+};
+
+#endif //VIEWER_INSTRUCTOR_H
|