From 543fec7ccffc004bb0ab82460a9410e1fb46f3c3 Mon Sep 17 00:00:00 2001 From: Monique Teillaud Date: Mon, 20 Dec 2010 13:31:30 +0000 Subject: [PATCH] new T3 demo using Qt4 and QGLViewer This demo was written in the framework of the GSoC by Fei (Sophie) Che, co-mentored by Manuel and me. --- .gitattributes | 40 + .../demo/Triangulation_3/CMakeLists.txt | 82 ++ .../demo/Triangulation_3/MainWindow.cpp | 243 +++ .../demo/Triangulation_3/MainWindow.h | 55 + .../demo/Triangulation_3/PreferenceDlg.cpp | 399 +++++ .../demo/Triangulation_3/PreferenceDlg.h | 70 + .../demo/Triangulation_3/Scene.cpp | 225 +++ Triangulation_3/demo/Triangulation_3/Scene.h | 40 + .../demo/Triangulation_3/T3_demo.cpp | 37 + .../demo/Triangulation_3/Viewer.cpp | 1297 +++++++++++++++++ Triangulation_3/demo/Triangulation_3/Viewer.h | 290 ++++ .../Triangulation_3/documentation/about.html | 13 + .../documentation/about_CGAL.html | 7 + .../Triangulation_3/icons/about_CGAL.html | 8 + .../demo/Triangulation_3/icons/cgal_logo.xpm | 24 + .../demo/Triangulation_3/icons/clear.jpeg | Bin 0 -> 843 bytes .../Triangulation_3/icons/coordinates.jpeg | Bin 0 -> 1268 bytes .../Triangulation_3/icons/empty_sphere.jpeg | Bin 0 -> 10703 bytes .../demo/Triangulation_3/icons/fileOpen.png | Bin 0 -> 1662 bytes .../demo/Triangulation_3/icons/fileSave.png | Bin 0 -> 1205 bytes .../demo/Triangulation_3/icons/flat.png | Bin 0 -> 2326 bytes .../demo/Triangulation_3/icons/grid.jpeg | Bin 0 -> 798 bytes .../demo/Triangulation_3/icons/insert.jpeg | Bin 0 -> 529 bytes .../Triangulation_3/icons/insert_point.jpg | Bin 0 -> 1685 bytes .../demo/Triangulation_3/icons/move_1.jpeg | Bin 0 -> 666 bytes .../demo/Triangulation_3/icons/nearest_nb.png | Bin 0 -> 3087 bytes .../Triangulation_3/icons/normal_view.jpeg | Bin 0 -> 797 bytes .../demo/Triangulation_3/icons/pause.jpeg | Bin 0 -> 1017 bytes .../demo/Triangulation_3/icons/play.jpeg | Bin 0 -> 799 bytes .../Triangulation_3/icons/pointRandom.png | Bin 0 -> 1585 bytes .../Triangulation_3/icons/preferences.jpeg | Bin 0 -> 1003 bytes .../demo/Triangulation_3/icons/quit.jpeg | Bin 0 -> 578 bytes .../Triangulation_3/icons/select_hand.jpeg | Bin 0 -> 3039 bytes .../Triangulation_3/icons/show_delaunay.jpeg | Bin 0 -> 5781 bytes .../Triangulation_3/icons/show_facet.jpeg | Bin 0 -> 1201 bytes .../Triangulation_3/icons/show_point.jpeg | Bin 0 -> 326 bytes .../Triangulation_3/icons/show_voronoi.jpeg | Bin 0 -> 2126 bytes .../demo/Triangulation_3/icons/stereo.png | Bin 0 -> 2350 bytes .../demo/Triangulation_3/icons/stop.jpeg | Bin 0 -> 891 bytes .../demo/Triangulation_3/typedefs.h | 101 ++ .../demo/Triangulation_3/ui_MainWindow.h | 584 ++++++++ 41 files changed, 3515 insertions(+) create mode 100644 Triangulation_3/demo/Triangulation_3/CMakeLists.txt create mode 100644 Triangulation_3/demo/Triangulation_3/MainWindow.cpp create mode 100644 Triangulation_3/demo/Triangulation_3/MainWindow.h create mode 100644 Triangulation_3/demo/Triangulation_3/PreferenceDlg.cpp create mode 100644 Triangulation_3/demo/Triangulation_3/PreferenceDlg.h create mode 100644 Triangulation_3/demo/Triangulation_3/Scene.cpp create mode 100644 Triangulation_3/demo/Triangulation_3/Scene.h create mode 100644 Triangulation_3/demo/Triangulation_3/T3_demo.cpp create mode 100644 Triangulation_3/demo/Triangulation_3/Viewer.cpp create mode 100644 Triangulation_3/demo/Triangulation_3/Viewer.h create mode 100644 Triangulation_3/demo/Triangulation_3/documentation/about.html create mode 100644 Triangulation_3/demo/Triangulation_3/documentation/about_CGAL.html create mode 100644 Triangulation_3/demo/Triangulation_3/icons/about_CGAL.html create mode 100644 Triangulation_3/demo/Triangulation_3/icons/cgal_logo.xpm create mode 100644 Triangulation_3/demo/Triangulation_3/icons/clear.jpeg create mode 100644 Triangulation_3/demo/Triangulation_3/icons/coordinates.jpeg create mode 100644 Triangulation_3/demo/Triangulation_3/icons/empty_sphere.jpeg create mode 100644 Triangulation_3/demo/Triangulation_3/icons/fileOpen.png create mode 100644 Triangulation_3/demo/Triangulation_3/icons/fileSave.png create mode 100644 Triangulation_3/demo/Triangulation_3/icons/flat.png create mode 100644 Triangulation_3/demo/Triangulation_3/icons/grid.jpeg create mode 100644 Triangulation_3/demo/Triangulation_3/icons/insert.jpeg create mode 100644 Triangulation_3/demo/Triangulation_3/icons/insert_point.jpg create mode 100644 Triangulation_3/demo/Triangulation_3/icons/move_1.jpeg create mode 100644 Triangulation_3/demo/Triangulation_3/icons/nearest_nb.png create mode 100644 Triangulation_3/demo/Triangulation_3/icons/normal_view.jpeg create mode 100644 Triangulation_3/demo/Triangulation_3/icons/pause.jpeg create mode 100644 Triangulation_3/demo/Triangulation_3/icons/play.jpeg create mode 100644 Triangulation_3/demo/Triangulation_3/icons/pointRandom.png create mode 100644 Triangulation_3/demo/Triangulation_3/icons/preferences.jpeg create mode 100644 Triangulation_3/demo/Triangulation_3/icons/quit.jpeg create mode 100644 Triangulation_3/demo/Triangulation_3/icons/select_hand.jpeg create mode 100644 Triangulation_3/demo/Triangulation_3/icons/show_delaunay.jpeg create mode 100644 Triangulation_3/demo/Triangulation_3/icons/show_facet.jpeg create mode 100644 Triangulation_3/demo/Triangulation_3/icons/show_point.jpeg create mode 100644 Triangulation_3/demo/Triangulation_3/icons/show_voronoi.jpeg create mode 100644 Triangulation_3/demo/Triangulation_3/icons/stereo.png create mode 100644 Triangulation_3/demo/Triangulation_3/icons/stop.jpeg create mode 100644 Triangulation_3/demo/Triangulation_3/typedefs.h create mode 100644 Triangulation_3/demo/Triangulation_3/ui_MainWindow.h diff --git a/.gitattributes b/.gitattributes index 7898f7d62d6..a3ce3a89545 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3904,6 +3904,46 @@ Triangulation_2/doc_tex/Triangulation_2_ref/remove.gif -text svneol=unset#image/ Triangulation_2/doc_tex/Triangulation_2_ref/walk.gif -text svneol=unset#image/gif Triangulation_2/include/CGAL/internal/Triangulation_euclidean_traits_projected_3.h -text Triangulation_2/test/Triangulation_2/test_delaunay_triangulation_proj.cpp -text +Triangulation_3/demo/Triangulation_3/CMakeLists.txt -text +Triangulation_3/demo/Triangulation_3/MainWindow.cpp -text +Triangulation_3/demo/Triangulation_3/MainWindow.h -text +Triangulation_3/demo/Triangulation_3/PreferenceDlg.cpp -text +Triangulation_3/demo/Triangulation_3/PreferenceDlg.h -text +Triangulation_3/demo/Triangulation_3/Scene.cpp -text +Triangulation_3/demo/Triangulation_3/Scene.h -text +Triangulation_3/demo/Triangulation_3/T3_demo.cpp -text +Triangulation_3/demo/Triangulation_3/Viewer.cpp -text +Triangulation_3/demo/Triangulation_3/Viewer.h -text +Triangulation_3/demo/Triangulation_3/documentation/about.html -text +Triangulation_3/demo/Triangulation_3/documentation/about_CGAL.html -text +Triangulation_3/demo/Triangulation_3/icons/about_CGAL.html -text +Triangulation_3/demo/Triangulation_3/icons/cgal_logo.xpm -text +Triangulation_3/demo/Triangulation_3/icons/clear.jpeg -text +Triangulation_3/demo/Triangulation_3/icons/coordinates.jpeg -text +Triangulation_3/demo/Triangulation_3/icons/empty_sphere.jpeg -text +Triangulation_3/demo/Triangulation_3/icons/fileOpen.png -text +Triangulation_3/demo/Triangulation_3/icons/fileSave.png -text +Triangulation_3/demo/Triangulation_3/icons/flat.png -text +Triangulation_3/demo/Triangulation_3/icons/grid.jpeg -text +Triangulation_3/demo/Triangulation_3/icons/insert.jpeg -text +Triangulation_3/demo/Triangulation_3/icons/insert_point.jpg -text +Triangulation_3/demo/Triangulation_3/icons/move_1.jpeg -text +Triangulation_3/demo/Triangulation_3/icons/nearest_nb.png -text +Triangulation_3/demo/Triangulation_3/icons/normal_view.jpeg -text +Triangulation_3/demo/Triangulation_3/icons/pause.jpeg -text +Triangulation_3/demo/Triangulation_3/icons/play.jpeg -text +Triangulation_3/demo/Triangulation_3/icons/pointRandom.png -text +Triangulation_3/demo/Triangulation_3/icons/preferences.jpeg -text +Triangulation_3/demo/Triangulation_3/icons/quit.jpeg -text +Triangulation_3/demo/Triangulation_3/icons/select_hand.jpeg -text +Triangulation_3/demo/Triangulation_3/icons/show_delaunay.jpeg -text +Triangulation_3/demo/Triangulation_3/icons/show_facet.jpeg -text +Triangulation_3/demo/Triangulation_3/icons/show_point.jpeg -text +Triangulation_3/demo/Triangulation_3/icons/show_voronoi.jpeg -text +Triangulation_3/demo/Triangulation_3/icons/stereo.png -text +Triangulation_3/demo/Triangulation_3/icons/stop.jpeg -text +Triangulation_3/demo/Triangulation_3/typedefs.h -text +Triangulation_3/demo/Triangulation_3/ui_MainWindow.h -text Triangulation_3/demo/Triangulation_3_Geomview_demos/CMakeLists.txt -text Triangulation_3/doc_tex/TriangulationDS_3/comborient.gif -text svneol=unset#image/gif Triangulation_3/doc_tex/TriangulationDS_3/comborient.pdf -text svneol=unset#application/pdf diff --git a/Triangulation_3/demo/Triangulation_3/CMakeLists.txt b/Triangulation_3/demo/Triangulation_3/CMakeLists.txt new file mode 100644 index 00000000000..c4d9fadfda5 --- /dev/null +++ b/Triangulation_3/demo/Triangulation_3/CMakeLists.txt @@ -0,0 +1,82 @@ +# Created by the script cgal_create_cmake_script +# This is the CMake script for compiling a CGAL application. + +project (Triangulation_demo_3) + +cmake_minimum_required(VERSION 2.4.5) + +set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) + +if ( COMMAND cmake_policy ) + cmake_policy( SET CMP0003 NEW ) +endif() + +find_package(CGAL COMPONENTS Qt4) +include(${CGAL_USE_FILE}) + +set( QT_USE_QTXML TRUE ) +set( QT_USE_QTMAIN TRUE ) +set( QT_USE_QTSCRIPT TRUE ) +set( QT_USE_QTOPENGL TRUE ) +set( QT_USE_QTASSISTANT TRUE ) +find_package(Qt4) + +find_package(OpenGL) + +if(QT4_FOUND) + include( ${QT_USE_FILE} ) + find_package(QGLViewer) +endif(QT4_FOUND) + +if ( CGAL_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND ) + + include(${QT_USE_FILE}) + + include_directories (${QGLVIEWER_INCLUDE_DIR}) + include_directories (BEFORE ../../include ./ ) + + # ui files, created with Qt Designer + qt4_wrap_ui( uis MainWindow.ui ) + + # qrc files (resources files, that contain icons, at least) + qt4_add_resources ( RESOURCE_FILES ./T3_demo.qrc ) + + # moc files (meta object compiler files, run moc preprocessor on the files with Widget defs) + qt4_automoc( MainWindow.cpp Viewer.cpp PreferenceDlg.cpp ) + + # cpp files + add_executable ( T3_demo T3_demo.cpp + MainWindow.cpp Viewer.cpp + PreferenceDlg.cpp + Scene.cpp ${uis} ${RESOURCE_FILES} ) + + add_to_cached_list( CGAL_EXECUTABLE_TARGETS T3_demo ) + + target_link_libraries( T3_demo ${CGAL_LIBRARIES} ${CGAL_3RD_PARTY_LIBRARIES}) + target_link_libraries( T3_demo ${QT_LIBRARIES} ${QGLVIEWER_LIBRARIES} ) + target_link_libraries( T3_demo ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} ) + +else( CGAL_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND ) + + set(TRIANGULATION_3_MISSING_DEPS "") + + if(NOT CGAL_FOUND) + set(TRIANGULATION_3_MISSING_DEPS "the CGAL Qt4 library, ${TRIANGULATION_3_MISSING_DEPS}") + endif() + + if(NOT QT4_FOUND) + set(TRIANGULATION_3_MISSING_DEPS "Qt4, ${TRIANGULATION_3_MISSING_DEPS}") + endif() + + if(NOT OPENGL_FOUND) + set(TRIANGULATION_3_MISSING_DEPS "OpenGL, ${TRIANGULATION_3_MISSING_DEPS}") + endif() + + if(NOT QGLVIEWER_FOUND) + set(TRIANGULATION_3_MISSING_DEPS "QGLViewer, ${TRIANGULATION_3_MISSING_DEPS}") + endif() + + + message(STATUS "NOTICE: This demo requires ${TRIANGULATION_3_MISSING_DEPS}and will not be compiled.") + +endif( CGAL_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND ) diff --git a/Triangulation_3/demo/Triangulation_3/MainWindow.cpp b/Triangulation_3/demo/Triangulation_3/MainWindow.cpp new file mode 100644 index 00000000000..1f1c271168e --- /dev/null +++ b/Triangulation_3/demo/Triangulation_3/MainWindow.cpp @@ -0,0 +1,243 @@ +#include "MainWindow.h" +#include + +#include "MainWindow.moc" // .moc will be the output from moc preprocessor + +MainWindow::MainWindow(QWidget* parent) + : CGAL::Qt::DemosMainWindow(parent) +{ + // Qt Automatic Connections + // http://doc.trolltech.com/4.4/designer-using-a-component.html#automatic-connections + // setupUi(this) automatically generates connections to the slots named + // "on__" + setupUi(this); + + this->viewer->setScene(&m_scene); + m_scene.setViewer(this->viewer); + + // setup Mode menu group actions + QActionGroup *modeGroup = new QActionGroup(this); + modeGroup->addAction(this->actionNormal_View); + modeGroup->addAction(this->actionInsert_Vertex); + modeGroup->addAction(this->actionInsert_Point); + modeGroup->addAction(this->actionSelect_Vertex); + modeGroup->addAction(this->actionMove_Vertex); + modeGroup->addAction(this->actionFind_NearestNb); + modeGroup->addAction(this->actionEmpty_Sphere); + QObject::connect(modeGroup, SIGNAL(triggered(QAction *)), this, SLOT(setMode(QAction *))); + + // connect menu actions to viewer slots + connectActions(); + + // About menu + // addAboutCGAL() is a function in DemoMainWindow + // it will add a menu action "About CGAL..." to Help menu and connect to popupAboutCGAL + // default popupAboutCGAL points to a fixed file directory ":/cgal/help/about_CGAL.html" + // here we override it with our directory + this->addAboutCGAL(); + // addAboutDemo(QString htmlResourceName) is also a function in DemoMainWindow + // it will add a menu action "About Demo..." to Help menu + // when the action is invoked, it will popup a messageBox showing the given html + this->addAboutDemo( "documentation/about.html" ); + + // read last setting from .ini file + viewer->readSettings(); +} + +void MainWindow::connectActions() +{ + // Edit menu actions + QObject::connect(this->actionIncremental_Construct, SIGNAL(toggled(bool)), + this->viewer, SLOT(toggleIncremental(bool))); + QObject::connect(this->actionStop_Animation, SIGNAL(triggered()), + this->viewer, SLOT(stopIncremental())); + QObject::connect(this->viewer, SIGNAL(stopIncAnimation()), + this, SLOT(stopAnimation())); + + // Show menu actions + QObject::connect(this->actionShow_Axis, SIGNAL(toggled(bool)), + this->viewer, SLOT(toggleShowAxis(bool))); + QObject::connect(this->actionShow_Vertex, SIGNAL(toggled(bool)), + this->viewer, SLOT(toggleShowVertex(bool))); + QObject::connect(this->actionShow_DEdge, SIGNAL(toggled(bool)), + this->viewer, SLOT(toggleShowDEdge(bool))); + QObject::connect(this->actionShow_VEdge, SIGNAL(toggled(bool)), + this->viewer, SLOT(toggleShowVEdge(bool))); + QObject::connect(this->actionShow_Facet, SIGNAL(toggled(bool)), + this->viewer, SLOT(toggleShowFacet(bool))); + QObject::connect(this->actionFlat, SIGNAL(toggled(bool)), + this->viewer, SLOT(toggleFlat(bool))); + + // Preferences + QObject::connect(this->actionPreferences, SIGNAL(triggered()), + this->viewer, SLOT(setPreferences())); + + // Help menu actions + QObject::connect(this->actionDemo_Help, SIGNAL(triggered()), + this->viewer, SLOT(help())); + QObject::connect(this->actionAbout_T3_demo, SIGNAL(triggered()), + this, SLOT(popupAboutDemo())); + + // Quit + QObject::connect(this->actionQuit, SIGNAL(triggered()), + qApp, SLOT(closeAllWindows())); + + // Viewer signals + QObject::connect(this, SIGNAL(sceneChanged()), + this->viewer, SLOT(updateGL())); +} + +void MainWindow::closeEvent(QCloseEvent *event) +{ + viewer->writeSettings(); +} + +/*************************************************************/ +/* Action functions */ + +void MainWindow::setMode(QAction *action) +{ + if( action == this->actionNormal_View ) + this->viewer->setMode( viewer->NONE ); + else if( action == this->actionInsert_Vertex ) + this->viewer->setMode( viewer->INSERT_V ); + else if( action == this->actionInsert_Point ) + this->viewer->setMode( viewer->INSERT_PT ); + else if( action == this->actionSelect_Vertex ) + this->viewer->setMode( viewer->SELECT ); + else if( action == this->actionMove_Vertex ) + this->viewer->setMode( viewer->MOVE ); + else if( action == this->actionFind_NearestNb ) + this->viewer->setMode( viewer->FINDNB ); + else if( action == this->actionEmpty_Sphere ) + this->viewer->setMode( viewer->EMPTYSPH ); +} + +void MainWindow::on_actionLoad_Points_triggered() +{ + QString fileName = QFileDialog::getOpenFileName(this, + tr("Open an file"), // dialog caption + ".", // initial directory + tr("OFF files (*.off);;XYZ files (*.xyz);;All files (*.*)")); // selection filter + if( fileName.isEmpty() ) return; + + // erase old data + viewer->clear(); + + // parse fileName to get the file type + std::string fname = fileName.toAscii().data(); + std::string ftype = fname.substr( fname.find_last_of('.')+1 ); + + if ( ftype.compare("off")==0 || ftype.compare("OFF")==0 ) { // read from OFF file + m_scene.loadPointsOFF( fname.data() ); + // set selectBuffer size (if necessary) + viewer->setSelBuffSize(); + } else if ( ftype.compare("xyz")==0 || ftype.compare("XYZ")==0 ) { // read from XYZ file + m_scene.loadPointsXYZ( fname.data() ); + // set selectBuffer size (if necessary) + viewer->setSelBuffSize(); + } else { + viewer->displayMessage( tr("Please select an OFF or XYZ file to open!") ); + } + + // update viewer + emit( sceneChanged() ); +} + +void MainWindow::on_actionSave_Points_triggered() +{ + if( m_scene.isDTEmpty() ) { + viewer->displayMessage( tr("Error: no existing triangulation to be saved.") ); + return; + } + + QString fileName = QFileDialog::getSaveFileName(this, + tr("Save an file"), // dialog caption + ".", // initial directory + tr("OFF files (*.off);;XYZ files (*.xyz);;All files (*.*)")); // selection filter + if( fileName.isEmpty() ) return; + + // parse fileName to get the file type + std::string fname = fileName.toAscii().data(); + std::string ftype = fname.substr( fname.find_last_of('.')+1 ); + + if ( ftype.compare("off")==0 || ftype.compare("OFF")==0 ) { // save to OFF file + m_scene.savePointsOFF( fname.data() ); + } else if ( ftype.compare("xyz")==0 || ftype.compare("XYZ")==0 ) { // save to XYZ file + m_scene.savePointsXYZ( fname.data() ); + } else { + viewer->displayMessage( tr("Please select an OFF or XYZ file to open!") ); + } +} + +void MainWindow::on_actionGenerate_Points_triggered() +{ + bool isOk; + int nPoints = QInputDialog::getInteger(this, + "3D Triangulation demo", "Number of points: ", // caption and label + 100, // default value + 4, // min value + 2147483647, // max value + 1, // step value of arrow button + &isOk); // if OK is pressed + + if ( isOk) { + // erase old data + viewer->clear(); + + // generate points + m_scene.generatePoints(nPoints); + // set selectBuffer size (if necessary) + viewer->setSelBuffSize(); + + // update viewer + emit( sceneChanged() ); + }// if(isOk) +} + +void MainWindow::stopAnimation() +{ + if( this->actionIncremental_Construct->isChecked() ) + this->actionIncremental_Construct->setChecked( false ); +} + +void MainWindow::on_actionClear_Scene_triggered() +{ + viewer->clear(); + + // update viewer + emit( sceneChanged() ); +} + +void MainWindow::popupAboutCGAL() +{ + // read contents from .html file + QFile about_CGAL( "documentation/about_CGAL.html" ); + about_CGAL.open(QIODevice::ReadOnly); + QString about_CGAL_txt = QTextStream(&about_CGAL).readAll(); +#ifdef CGAL_VERSION_STR + about_CGAL_txt.replace("", + QString(" (version %1, svn r%2)") + .arg(CGAL_VERSION_STR).arg(CGAL_SVN_REVISION)); +#endif + + // popup a message box + QMessageBox mb(QMessageBox::NoIcon, + tr("About CGAL..."), + about_CGAL_txt, + QMessageBox::Ok, + this); + + // set links to be accessible by mouse or keyboard + QLabel* mb_label = mb.findChild("qt_msgbox_label"); + if(mb_label) { + mb_label->setTextInteractionFlags(mb_label->textInteractionFlags() | + ::Qt::LinksAccessibleByMouse | + ::Qt::LinksAccessibleByKeyboard); + } else { + std::cerr << "Cannot find child \"qt_msgbox_label\" in QMessageBox\n" + << " with Qt version " << QT_VERSION_STR << "!\n"; + } + + mb.exec(); +} diff --git a/Triangulation_3/demo/Triangulation_3/MainWindow.h b/Triangulation_3/demo/Triangulation_3/MainWindow.h new file mode 100644 index 00000000000..a033fbb5b70 --- /dev/null +++ b/Triangulation_3/demo/Triangulation_3/MainWindow.h @@ -0,0 +1,55 @@ +#ifndef MAIN_WINDOW_H +#define MAIN_WINDOW_H + +#include "ui_MainWindow.h" +#include +#include +#include +#include + +#include + +#include "Scene.h" + +class QWidget; + +class MainWindow : public CGAL::Qt::DemosMainWindow, private Ui::MainWindow +{ + Q_OBJECT + +public: + MainWindow(QWidget* parent = 0); + ~MainWindow() {} + +public slots: + // file menu + void on_actionLoad_Points_triggered(); + void on_actionSave_Points_triggered(); + + // edit menu + void on_actionGenerate_Points_triggered(); + void stopAnimation(); + + // mode menu + void setMode(QAction *a); + + // show menu + void on_actionClear_Scene_triggered(); + + // about menu + void popupAboutCGAL(); + + signals: + void sceneChanged(); + +protected: + void closeEvent(QCloseEvent *event); + +private: + void connectActions(); + +private: + Scene m_scene; +}; + +#endif diff --git a/Triangulation_3/demo/Triangulation_3/PreferenceDlg.cpp b/Triangulation_3/demo/Triangulation_3/PreferenceDlg.cpp new file mode 100644 index 00000000000..dca25d9ce5f --- /dev/null +++ b/Triangulation_3/demo/Triangulation_3/PreferenceDlg.cpp @@ -0,0 +1,399 @@ +#include +#include "PreferenceDlg.h" + +#include "PreferenceDlg.moc" // .moc will be the output from moc preprocessor + +PreferenceDlg::PreferenceDlg(QWidget *parent) : QDialog(parent) +{ + /* Vertex */ + + // create groupbox + QGroupBox *groupV = new QGroupBox( tr("Vertex") ); + // create buttons + QPushButton *btnVertex = new QPushButton( tr("Set Color") ); + // create color label + m_labelVertex = new QLabel; + m_labelVertex->setFrameStyle(QFrame::Sunken | QFrame::Panel); + // create size label + QLabel *labelSizeV = new QLabel( tr("Set Size") ); + // create lineedit + m_editSizeV = new QLineEdit; + + // connect to actions + connect( btnVertex, SIGNAL(clicked()), this, SLOT(setVertexColor()) ); + connect( m_editSizeV, SIGNAL(textChanged(const QString&)), this, SLOT(setVertexSize(const QString&)) ); + + // lay out the buttons + QGridLayout *layoutV = new QGridLayout; + layoutV->addWidget( btnVertex, 0, 0 ); + layoutV->addWidget( m_labelVertex, 0, 1 ); + layoutV->addWidget( labelSizeV, 1, 0 ); + layoutV->addWidget( m_editSizeV, 1, 1 ); + groupV->setLayout( layoutV ); + + /* Delaunau Edge */ + + // create groupbox + QGroupBox *groupDE = new QGroupBox( tr("Delaunay Edge") ); + // create button + QPushButton *btnDEdge = new QPushButton( tr("Set Color") ); + // create color label + m_labelDEdge = new QLabel; + m_labelDEdge->setFrameStyle(QFrame::Sunken | QFrame::Panel); + // create size label + QLabel *labelSizeDE = new QLabel( tr("Set Size") ); + // create lineedit + m_editSizeDE = new QLineEdit; + + // connect to actions + connect( btnDEdge, SIGNAL(clicked()), this, SLOT(setDEdgeColor()) ); + connect( m_editSizeDE, SIGNAL(textChanged(const QString&)), this, SLOT(setDEdgeSize(const QString&)) ); + + // lay out the buttons + QGridLayout *layoutDE = new QGridLayout; + layoutDE->addWidget( btnDEdge, 0, 0 ); + layoutDE->addWidget( m_labelDEdge, 0, 1 ); + layoutDE->addWidget( labelSizeDE, 1, 0 ); + layoutDE->addWidget( m_editSizeDE, 1, 1 ); + groupDE->setLayout( layoutDE ); + + /* Voronoi Edge */ + + // create groupbox + QGroupBox *groupVE = new QGroupBox( tr("Voronoi Edge") ); + // create button + QPushButton *btnVEdge = new QPushButton( tr("Set Color") ); + // create color label + m_labelVEdge = new QLabel; + m_labelVEdge->setFrameStyle(QFrame::Sunken | QFrame::Panel); + // create size label + QLabel *labelSizeVE = new QLabel( tr("Set Size") ); + // create lineedit + m_editSizeVE = new QLineEdit; + + // connect to actions + connect( btnVEdge, SIGNAL(clicked()), this, SLOT(setVEdgeColor()) ); + connect( m_editSizeVE, SIGNAL(textChanged(const QString&)), this, SLOT(setVEdgeSize(const QString&)) ); + + // lay out the buttons + QGridLayout *layoutVE = new QGridLayout; + layoutVE->addWidget( btnVEdge, 0, 0 ); + layoutVE->addWidget( m_labelVEdge, 0, 1 ); + layoutVE->addWidget( labelSizeVE, 1, 0 ); + layoutVE->addWidget( m_editSizeVE, 1, 1 ); + groupVE->setLayout( layoutVE ); + + /* Facet */ + + // create groupbox + QGroupBox *groupF = new QGroupBox( tr("Facet") ); + // create button + QPushButton *btnFacet = new QPushButton( tr("Set Color") ); + // create color label + m_labelFacet = new QLabel; + m_labelFacet->setFrameStyle(QFrame::Sunken | QFrame::Panel); + // create label and spinbox + QLabel *labelFacetA = new QLabel( tr("Transparency") ); + m_spinAlphaF = new QSpinBox; + m_spinAlphaF->setRange(0, 255); + + // connect to actions + connect( btnFacet, SIGNAL(clicked()), this, SLOT(setFacetColor()) ); + connect( m_spinAlphaF, SIGNAL(valueChanged(int)), this, SLOT(setFacetAlpha()) ); + + // lay out the buttons + QGridLayout *layoutF = new QGridLayout; + layoutF->addWidget( btnFacet, 0, 0 ); + layoutF->addWidget( m_labelFacet, 0, 1 ); + layoutF->addWidget( labelFacetA, 1, 0 ); + layoutF->addWidget( m_spinAlphaF, 1, 1 ); + groupF->setLayout( layoutF ); + + /* Trackball */ + + // create groupbox + QGroupBox *groupB = new QGroupBox( tr("Trackball") ); + // create button + QPushButton *btnBall = new QPushButton( tr("Set Color") ); + // create color label + m_labelBall = new QLabel; + m_labelBall->setFrameStyle(QFrame::Sunken | QFrame::Panel); + // create label and spinbox + QLabel *labelBallA = new QLabel( tr("Transparency") ); + m_spinAlphaB = new QSpinBox; + m_spinAlphaB->setRange(0, 255); + // create label and spinbox + QLabel *labelStep = new QLabel( tr("Step-long of Resizing") ); + m_spinStep = new QSpinBox; + m_spinStep->setRange(1, 300); + + // connect to actions + connect( btnBall, SIGNAL(clicked()), this, SLOT(setTrackballColor()) ); + connect( m_spinAlphaB, SIGNAL(valueChanged(int)), this, SLOT(setTrackballAlpha()) ); + connect( m_spinStep, SIGNAL(valueChanged(int)), this, SLOT(setStepLong()) ); + + // lay out the buttons + QGridLayout *layoutB = new QGridLayout; + layoutB->addWidget( btnBall, 0, 0 ); + layoutB->addWidget( m_labelBall, 0, 1 ); + layoutB->addWidget( labelBallA, 1, 0 ); + layoutB->addWidget( m_spinAlphaB, 1, 1 ); + layoutB->addWidget( labelStep, 2, 0 ); + layoutB->addWidget( m_spinStep, 2, 1 ); + groupB->setLayout( layoutB ); + + /* Empty Sphere */ + + // create groupbox + QGroupBox *groupS = new QGroupBox( tr("Empty Sphere") ); + // create color label + m_labelSphere = new QLabel; + m_labelSphere->setFrameStyle(QFrame::Sunken | QFrame::Panel); + // create button + QPushButton *btnSphere = new QPushButton( tr("Set Color") ); + // create label and spinbox + QLabel *labelSphereA = new QLabel( tr("Transparency") ); + m_spinAlphaS = new QSpinBox; + m_spinAlphaS->setRange(0, 255); + + // connect to actions + connect( btnSphere, SIGNAL(clicked()), this, SLOT(setEmptySphereColor()) ); + connect( m_spinAlphaS, SIGNAL(valueChanged(int)), this, SLOT(setEmptySphereAlpha()) ); + + // lay out the buttons + QGridLayout *layoutS = new QGridLayout; + layoutS->addWidget( btnSphere, 0, 0 ); + layoutS->addWidget( m_labelSphere, 0, 1 ); + layoutS->addWidget( labelSphereA, 1, 0 ); + layoutS->addWidget( m_spinAlphaS, 1, 1 ); + groupS->setLayout( layoutS ); + + /* OK buttons */ + // create groupbox + QGroupBox *groupBtn = new QGroupBox(); + // buttons + QPushButton *ok = new QPushButton( tr("OK") ); + QPushButton *apply = new QPushButton( tr("Apply") ); + QPushButton *cancel = new QPushButton( tr("Cancel") ); + cancel->setFocus(); + + // connect to actions + connect( ok, SIGNAL(clicked()), this, SLOT(okClicked()) ); + connect( apply, SIGNAL(clicked()), this, SLOT(applyClicked()) ); + connect( cancel, SIGNAL(clicked()), this, SLOT(reject()) ); + + // lay out the buttons + QGridLayout *layoutBtn = new QGridLayout; + layoutBtn->addWidget( ok, 0, 0 ); + layoutBtn->addWidget( cancel, 0, 1 ); + layoutBtn->addWidget( apply, 0, 2 ); + groupBtn->setLayout( layoutBtn ); + + /* dialog layout */ + + // lay out the buttons + QGridLayout *main = new QGridLayout; + main->addWidget( groupV, 0, 1 ); + main->addWidget( groupDE, 0, 2 ); + main->addWidget( groupVE, 0, 3 ); + main->addWidget( groupF, 1, 1 ); + main->addWidget( groupB, 1, 2 ); + main->addWidget( groupS, 1, 3 ); + main->addWidget( groupBtn, 2, 2, 2, 3 ); + setLayout( main ); + + // set dialog title + setWindowTitle( tr("Preferences") ); +} + +void PreferenceDlg::init(QColor clrVt, float sizeV, QColor clrDE, float sizeDE, + QColor clrVE, float sizeVE, + QColor clrF, QColor clrB, QColor clrS, int iStep) +{ + // vertex color + m_colorVertex = clrVt; + // show the color in label + m_labelVertex->setText(m_colorVertex.name()); + m_labelVertex->setPalette( QPalette(m_colorVertex) ); + m_labelVertex->setAutoFillBackground(true); + // vertex size + m_fSizeVertex = sizeV; + m_editSizeV->setText( QString::number( m_fSizeVertex ) ); + + // Delaunay edge color + m_colorDEdge = clrDE; + // show the color in label + m_labelDEdge->setText( m_colorDEdge.name() ); + m_labelDEdge->setPalette( QPalette(m_colorDEdge) ); + m_labelDEdge->setAutoFillBackground(true); + // edge size + m_fSizeDEdge = sizeDE; + m_editSizeDE->setText( QString::number( m_fSizeDEdge ) ); + + // Voronoi edge color + m_colorVEdge = clrVE; + // show the color in label + m_labelVEdge->setText( m_colorVEdge.name() ); + m_labelVEdge->setPalette( QPalette(m_colorVEdge) ); + m_labelVEdge->setAutoFillBackground(true); + // edge size + m_fSizeVEdge = sizeVE; + m_editSizeVE->setText( QString::number( m_fSizeVEdge ) ); + + // facet color + m_colorFacet = clrF; + // show the color in label + m_labelFacet->setText( m_colorFacet.name() ); + m_labelFacet->setPalette( QPalette(m_colorFacet) ); + m_labelFacet->setAutoFillBackground(true); + // facet transparency + m_spinAlphaF->setValue( m_colorFacet.alpha() ); + + // trackball color + m_colorTrackball = clrB; + // show the color in label + m_labelBall->setText(m_colorTrackball.name()); + m_labelBall->setPalette( QPalette(m_colorTrackball) ); + m_labelBall->setAutoFillBackground(true); + // trackball transparency + m_spinAlphaB->setValue( m_colorTrackball.alpha() ); + // trackball resizing fineness + m_spinStep->setValue( iStep ); + + // empty sphere color + m_colorEmptySphere = clrS; + // show the color in label + m_labelSphere->setText(m_colorEmptySphere.name()); + m_labelSphere->setPalette( QPalette(m_colorEmptySphere) ); + m_labelSphere->setAutoFillBackground(true); + // trackball transparency + m_spinAlphaS->setValue( m_colorEmptySphere.alpha() ); +} + +void PreferenceDlg::setVertexColor() +{ + m_colorVertex = QColorDialog::getColor(m_colorVertex, this); + if( m_colorVertex.isValid() ) { + m_labelVertex->setText(m_colorVertex.name()); + m_labelVertex->setPalette( QPalette(m_colorVertex) ); + m_labelVertex->setAutoFillBackground(true); + } +} + +void PreferenceDlg::setVertexSize(const QString& str) +{ + bool ok; + float size = str.toFloat(&ok); + if( ok ) + m_fSizeVertex = size; + else { + QMessageBox mb(QMessageBox::NoIcon, tr("Error!"), + tr("Enter a valid floating number."), + QMessageBox::Ok, this); + mb.exec(); + m_editSizeV->setFocus(); + } +} + +void PreferenceDlg::setDEdgeColor() +{ + m_colorDEdge = QColorDialog::getColor(m_colorDEdge, this); + if( m_colorDEdge.isValid() ) { + m_labelDEdge->setText( m_colorDEdge.name() ); + m_labelDEdge->setPalette( QPalette(m_colorDEdge) ); + m_labelDEdge->setAutoFillBackground(true); + } +} + +void PreferenceDlg::setDEdgeSize(const QString& str) +{ + bool ok; + float size = str.toFloat(&ok); + if( ok ) + m_fSizeDEdge = size; + else { + QMessageBox mb(QMessageBox::NoIcon, tr("Error!"), + tr("Enter a valid floating number."), + QMessageBox::Ok, this); + mb.exec(); + m_editSizeDE->setFocus(); + } +} + +void PreferenceDlg::setVEdgeColor() +{ + m_colorVEdge = QColorDialog::getColor(m_colorVEdge, this); + if( m_colorVEdge.isValid() ) { + m_labelVEdge->setText( m_colorVEdge.name() ); + m_labelVEdge->setPalette( QPalette(m_colorVEdge) ); + m_labelVEdge->setAutoFillBackground(true); + } +} + +void PreferenceDlg::setVEdgeSize(const QString& str) +{ + bool ok; + float size = str.toFloat(&ok); + if( ok ) + m_fSizeVEdge = size; + else { + QMessageBox mb(QMessageBox::NoIcon, tr("Error!"), + tr("Enter a valid floating number."), + QMessageBox::Ok, this); + mb.exec(); + m_editSizeVE->setFocus(); + } +} + +void PreferenceDlg::setFacetColor() +{ + m_colorFacet = QColorDialog::getColor(m_colorFacet, this); + if( m_colorFacet.isValid() ) { + m_labelFacet->setText( m_colorFacet.name() ); + m_colorFacet.setAlpha( m_spinAlphaF->value() ); + m_labelFacet->setPalette( QPalette(m_colorFacet) ); + m_labelFacet->setAutoFillBackground(true); + } +} + +void PreferenceDlg::setFacetAlpha() +{ + m_colorFacet.setAlpha( m_spinAlphaF->value() ); +} + +void PreferenceDlg::setTrackballColor() +{ + m_colorTrackball = QColorDialog::getColor(m_colorTrackball, this); + if( m_colorTrackball.isValid() ) { + m_labelBall->setText( m_colorTrackball.name() ); + m_colorTrackball.setAlpha( m_spinAlphaB->value() ); + m_labelBall->setPalette( QPalette(m_colorTrackball) ); + m_labelBall->setAutoFillBackground(true); + } +} + +void PreferenceDlg::setTrackballAlpha() +{ + m_colorTrackball.setAlpha( m_spinAlphaB->value() ); +} + +void PreferenceDlg::setStepLong() +{ + m_iStep = m_spinStep->value(); +} + +void PreferenceDlg::setEmptySphereColor() +{ + m_colorEmptySphere = QColorDialog::getColor(m_colorEmptySphere, this); + if( m_colorEmptySphere.isValid() ) { + m_labelSphere->setText( m_colorEmptySphere.name() ); + m_colorEmptySphere.setAlpha( m_spinAlphaS->value() ); + m_labelSphere->setPalette( QPalette(m_colorEmptySphere) ); + m_labelSphere->setAutoFillBackground(true); + } +} + +void PreferenceDlg::setEmptySphereAlpha() +{ + m_colorEmptySphere.setAlpha( m_spinAlphaS->value() ); +} diff --git a/Triangulation_3/demo/Triangulation_3/PreferenceDlg.h b/Triangulation_3/demo/Triangulation_3/PreferenceDlg.h new file mode 100644 index 00000000000..d4ab184fac1 --- /dev/null +++ b/Triangulation_3/demo/Triangulation_3/PreferenceDlg.h @@ -0,0 +1,70 @@ +#ifndef PREFERENCE_DLG_H +#define PREFERENCE_DLG_H + +#include + +class QLabel; +class QSpinBox; +class QLineEdit; + +class PreferenceDlg : public QDialog +{ + Q_OBJECT + + friend class Viewer; + +public: + PreferenceDlg(QWidget *parent=0); + +private: + void init(QColor, float, QColor, float, QColor, float, QColor, QColor, QColor, int); + +private slots: + void okClicked() { hide(); emit( applyChanges() ); } + void applyClicked() { emit( applyChanges() ); } + + void setVertexColor(); + void setVertexSize(const QString&); + void setDEdgeColor(); + void setDEdgeSize(const QString&); + void setVEdgeColor(); + void setVEdgeSize(const QString&); + void setFacetColor(); + void setFacetAlpha(); + void setTrackballColor(); + void setTrackballAlpha(); + void setStepLong(); + void setEmptySphereColor(); + void setEmptySphereAlpha(); + + signals: // Signals do not have access specifier + void applyChanges(); + +private: + QLabel *m_labelVertex; + QLineEdit *m_editSizeV; + QLabel *m_labelDEdge; + QLineEdit *m_editSizeDE; + QLabel *m_labelVEdge; + QLineEdit *m_editSizeVE; + QLabel *m_labelFacet; + QSpinBox *m_spinAlphaF; + QLabel *m_labelBall; + QSpinBox *m_spinAlphaB; + QSpinBox *m_spinStep; + QLabel *m_labelSphere; + QSpinBox *m_spinAlphaS; + + float m_fSizeVertex; + float m_fSizeDEdge; + float m_fSizeVEdge; + QColor m_colorVertex; + QColor m_colorDEdge; + QColor m_colorVEdge; + QColor m_colorFacet; + QColor m_colorTrackball; + int m_iStep; + QColor m_colorEmptySphere; +}; + +#endif diff --git a/Triangulation_3/demo/Triangulation_3/Scene.cpp b/Triangulation_3/demo/Triangulation_3/Scene.cpp new file mode 100644 index 00000000000..ffb03f63a0b --- /dev/null +++ b/Triangulation_3/demo/Triangulation_3/Scene.cpp @@ -0,0 +1,225 @@ +#include "Scene.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +void Scene::generatePoints(int num) +{ + if(num <= 0) return; + + /* Generate 'num' points: */ + /* 1. randomly in the cube [ (-1,-1,-1), (1,1,1) ] --tested */ + CGAL::Random_points_in_cube_3 pts_generator(1.0); + /* 2. randomly on a sphere of radius 1.0 --tested */ + // CGAL::Random_points_in_sphere_3 pts_generator(1.0); + + /* Insert them into the point list: */ + /* 1. use CGAL's copy function --tested */ + list pts; + CGAL::copy_n( pts_generator, num, std::back_inserter(pts) ); + /* 2. use STL's function */ + //for (int i=0; i & points) +{ + ifstream fin; + fin.open( filename ); + // Check whether the file is opened properly + if( !fin ) { + showError( QObject::tr("Error: cannot open file %1 for reading.").arg(filename) ); + return; + } + + istream *pIn = &fin; + + // Use CGAL::File_scanner_OFF to read in data + CGAL::File_scanner_OFF scanner(*pIn); + if( !(*pIn) ) { + showError( QObject::tr("Input error: file %1 is not in OFF format.").arg(filename) ); + return; + } + if( scanner.size_of_vertices() <= 0 ) { + showError( QObject::tr("Input error: file %1 has no vertices.").arg(filename) ); + return; + } + // Get points data from scanner + double x, y, z; + for(int i=0; i pts; + + /* Read point data from file */ + /* 1. use CGAL::File_scanner_OFF to read in data --tested */ + readOFFPointsandFacets( filename, pts ); + + /* 2. use CGAL::read_off_points to read in data -- tested */ + /* Note: read in points only, i.e. normals and faces are ignored */ + /* Note: this function can NOT omit comments (starting with '#') */ +// ifstream fin; +// fin.open( filename ); + // check whether the file is opened properly +// if( !fin ) { +// showError( QObject::tr("Error: cannot open file %1 for reading.").arg(filename) ); +// return; +// } +// if ( !CGAL::read_off_points( fin, // inout ifstream +// back_inserter(pts) ) ) { // output iterator over points +// showError( QObject::tr("Error: cannot read file %1.").arg(filename) ); +// } + + /* Insert the points to build a Delaunay triangulation */ + /* Note: this function returns the number of inserted points; + it is not guaranteed to insert the points following the order of iteraror. */ + m_dt.insert( pts.begin(), pts.end() ); + /* Check the combinatorial validity of the triangulation */ + /* Note: when it is set to be true, + messages describing the first invalidity encountered are printed. */ + if( !m_dt.is_valid() ) // default: false - verbosity off + showError( QObject::tr("Error: fail to build a Delaunay triangulation.") ); + /* Check the dimension */ + if( m_dt.dimension() != 3 ) + showError( QObject::tr("Error: cannot built a 3D triangulation.") ); + /* Store the vertex handles into an array for future usage (move, delete, etc) */ + for(vertices_iterator vit=m_dt.finite_vertices_begin(); + vit!=m_dt.finite_vertices_end(); ++vit) { + m_vhArray.push_back( vit ); + } + assert( m_dt.number_of_vertices() == m_vhArray.size() ); +} + +void Scene::loadPointsXYZ(const char* filename) +{ + ifstream fin; + fin.open( filename ); + // Check whether the file is opened properly + if( !fin ) { + showError( QObject::tr("Error: cannot open file %1 for reading.").arg(filename) ); + return; + } + + /* Use CGAL::read_xyz_points to read in data -- tested */ + /* Note: this function reads in points only (normals are ignored) */ + /* Note: this function can NOT omit comments (starting with '#') */ + list pts; + if( !CGAL::read_xyz_points( fin, // input ifstream + back_inserter(pts) ) ) { // output iterator over points + showError( QObject::tr("Error: cannot read file %1.").arg(filename) ); + } + + /* Insert the points to build a Delaunay triangulation */ + /* Note: this function returns the number of inserted points; + it is not guaranteed to insert the points following the order of iteraror. */ + m_dt.insert( pts.begin(), pts.end() ); + /* Check the combinatorial validity of the triangulation */ + /* Note: when it is set to be true, + messages describing the first invalidity encountered are printed. */ + if( !m_dt.is_valid() ) // default: false - verbosity off + showError( QObject::tr("Error: fail to build a Delaunay triangulation.") ); + /* Check the dimension */ + if( m_dt.dimension() != 3 ) + showError( QObject::tr("Error: cannot build a 3D triangulation.") ); + /* Store the vertex handles into an array for future usage (move, delete, etc) */ + for(vertices_iterator vit=m_dt.finite_vertices_begin(); + vit!=m_dt.finite_vertices_end(); ++vit) { + m_vhArray.push_back( vit ); + } + assert( m_dt.number_of_vertices() == m_vhArray.size() ); +} + +void Scene::savePointsOFF(const char* filename) +{ + ofstream fout; + fout.open( filename ); + if( !fout ) { + showError( QObject::tr("Error: cannot open file %1 for writting.").arg(filename) ); + return; + } + + ostream *pOut = &fout; + + /* Use CGAL::File_writer_OFF to write points */ + // initialize header_OFF + CGAL::File_header_OFF header(false, // true: binary output; false: ASCII + false, // true: no comments in file + false, // true: Geomview SKEL format + true); // true: verbosity on; false: verbosity off + // a simpler way to initialize header_OFF +// CGAL::File_header_OFF header(true); // true: verbosity on +// // (ASCII output, comments, no SKEL) + CGAL::File_writer_OFF writer( header ); + // write header + writer.write_header(*pOut, // output ostream + m_dt.number_of_vertices(), // number of points/vertices + 0, // number of halfedges + 0, // number of facets + false); // true: has normals + // write points (get from point array) + for(vertices_iterator vit=m_dt.finite_vertices_begin(); + vit!=m_dt.finite_vertices_end(); ++vit) { + Point_3& p = vit->point(); + writer.write_vertex( p.x(), p.y(), p.z() ); + } + // write footer + writer.write_footer(); +} + +void Scene::savePointsXYZ(const char* filename) +{ + ofstream fout; + fout.open( filename ); + // Check whether the file is opened properly + if( !fout ) { + showError( QObject::tr("Error: cannot open file %1 for writting.").arg(filename) ); + return; + } + + /* Use CGAL::write_xyz_points to write out data */ + /* Note: this function writes out points only (normals are ignored) */ + if( !CGAL::write_xyz_points( fout, // output ofstream + m_dt.points_begin(), // first output point + m_dt.points_end() ) ) { // past-the-end output point + showError( QObject::tr("Error: cannot read file %1.").arg(filename) ); + } +} diff --git a/Triangulation_3/demo/Triangulation_3/Scene.h b/Triangulation_3/demo/Triangulation_3/Scene.h new file mode 100644 index 00000000000..2401e336c3c --- /dev/null +++ b/Triangulation_3/demo/Triangulation_3/Scene.h @@ -0,0 +1,40 @@ +#ifndef SCENE_H +#define SCENE_H + +#include "typedefs.h" +#include + +class Scene { + + friend class Viewer; + +public: + Scene() {} + ~Scene() { eraseOldData(); } + +public: + inline void setViewer(QGLViewer* v) { m_viewer = v; } + inline void showError(const QString & msg) { + if(!m_viewer) m_viewer->displayMessage( msg ); + } + inline bool isDTEmpty() { return m_dt.number_of_vertices()==0; } + inline void eraseOldData() { m_dt.clear(); m_vhArray.clear(); } + +public: + void generatePoints(int); + void loadPointsOFF(const char*); + void loadPointsXYZ(const char*); + void savePointsOFF(const char*); + void savePointsXYZ(const char*); + + void readOFFPointsandFacets(const char*, std::list &); + +private: + //added for T3 demo + DT3 m_dt; + QList m_vhArray; + + QGLViewer* m_viewer; +}; + +#endif diff --git a/Triangulation_3/demo/Triangulation_3/T3_demo.cpp b/Triangulation_3/demo/Triangulation_3/T3_demo.cpp new file mode 100644 index 00000000000..a79e94031d2 --- /dev/null +++ b/Triangulation_3/demo/Triangulation_3/T3_demo.cpp @@ -0,0 +1,37 @@ +// Copyright (c) 2010 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org); you may redistribute it under +// the terms of the Q Public License version 1.0. +// See the file LICENSE.QPL distributed with CGAL. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL: svn+ssh://sccode@scm.gforge.inria.fr/svn/cgal/branches/experimental-packages/GSoC10-demoT3/demos/Triangulation_demo_3/ $ +// $Id: r58170 2010-08-19 20:46:16 -0400 $ +// +// +// Author(s) : Sophie Fei Che +// +// File Description : Demo of CGAL 3D Triangulation package + +#include "MainWindow.h" +#include + +int main(int argc, char** argv) +{ + QApplication app(argc, argv); + + app.setOrganizationDomain("inria.fr"); + app.setOrganizationName("INRIA"); + app.setApplicationName("3D Triangulation Demo"); + + MainWindow mw; + mw.show(); + + return app.exec(); +} diff --git a/Triangulation_3/demo/Triangulation_3/Viewer.cpp b/Triangulation_3/demo/Triangulation_3/Viewer.cpp new file mode 100644 index 00000000000..068ce983961 --- /dev/null +++ b/Triangulation_3/demo/Triangulation_3/Viewer.cpp @@ -0,0 +1,1297 @@ +#include "Viewer.h" + +using namespace std; + +#include "Viewer.moc" // .moc will be the output from moc preprocessor + +void Viewer::init() +{ + /* Initial timer for playing incremental construction */ + m_pTimer = new QTimer(this); + connect(m_pTimer, SIGNAL(timeout()), this, SLOT(incremental_insert())); + + /* Scene inits */ + setBackgroundColor(::Qt::white); + // scene are defined by a sphere of 2.0, camera at the center, i.e. (0, 0, 0) + setSceneCenter( qglviewer::Vec(-0.,-0.,-0.) ); + setSceneRadius( 2. ); + // show text message + setTextIsEnabled(true); + setForegroundColor(::Qt::red); + setFont(QFont("Arial Black", 16, QFont::Bold)); + + /* OpenGL inits */ + // Increase the material shininess, so that the difference between + // the two versions of the spiral is more visible. + glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 50.0); + GLfloat specular_color[4] = { 0.8f, 0.8f, 0.8f, 1.0 }; + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular_color); + // Set Smooth Shading + ::glShadeModel(GL_SMOOTH); + + // depth buffer setup + ::glClearDepth(1.0f); + ::glEnable(GL_DEPTH_TEST); + ::glDepthFunc(GL_LEQUAL); + ::glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + + // enable semi-transparent culling planes + ::glEnable(GL_BLEND); + ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + // anti-aliasing, i.e. reduce jaggedness (if the OpenGL driver permits that) + ::glEnable(GL_POINT_SMOOTH); + ::glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); + ::glEnable(GL_LINE_SMOOTH); + ::glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); + + /* Add mouse and key description */ + setKeyDescription( Qt::CTRL + Qt::Key_G, tr("Generate points") ); + setKeyDescription( Qt::CTRL + Qt::Key_O, tr("Load points") ); + setKeyDescription( Qt::CTRL + Qt::Key_S, tr("Save points") ); + setKeyDescription( Qt::CTRL + Qt::Key_Comma, tr("Preference") ); + setKeyDescription( Qt::CTRL + Qt::Key_H, tr("Hide Kernel Demo") ); + setKeyDescription( Qt::CTRL + Qt::Key_Q, tr("Quit Kernel Demo") ); + setKeyDescription( Qt::Key_Return, + tr("Insert new point to triangulation in Input-Point mode") ); + setKeyDescription( Qt::Key_Escape, + tr("Cancel insertion in Input-Point mode;
") + + tr("Cancel current selection in Select mode") ); + setKeyDescription( Qt::Key_Delete, tr("Delete selected vertices in Select mode") ); + + setMouseBindingDescription( Qt::LeftButton, + tr("Hold to move new point in Input-Point mode;
") + + tr("Hold to move a vertex in Move mode") ); + setMouseBindingDescription( Qt::SHIFT + Qt::LeftButton, + tr("Click to insert a vertex in Input-Vertex mode;
") + + tr("Click to insert a point in Input-Point mode;
") + + tr("Click or Drag to select multiple points in Select mode;
") + + tr("Click to place a query point in Find-Nearest-Neighbor mode;
") + + tr("Click to place a query point in Show-Empty-Sphere mode") ); + setMouseBindingDescription( Qt::CTRL + Qt::LeftButton, + tr("Drag to add vertices to current selection in Select mode") ); +} + +QString Viewer::helpString() const +{ + QString text("

3D Triangulation Demo

"); + + text += "This example illustrates a generic interactive demo for 3D Triangulation in CGAL. "; + text += "This demo could be used as a simple skeleton "; + text += "for potential demos of other 3D packages or for teaching CGAL.

"; + + text += "The key feature is to edit vertices/points with mouse."; + text += "There are several modes:

"; + + text += " - Normal Mode: "; + text += "Rotate, zoom, or translate camera using mouse.
"; + text += " - Insert Vertex: "; + text += "Insert a vertex on the surface of the trackball "; + text += "and the triangulation will be updated correspondingly.
"; + text += " - Insert Point: "; + text += "Insert a point on the surface of the trackball. "; + text += "Its conflict region will be highlighted. "; + text += "When the new point is moving, "; + text += "its conflict region will be updated correspondingly.
"; + text += " - Select: "; + text += "Click or drag mouse left button to select multiple points.
"; + text += " - Move: Hold mouse left button to move a vertex "; + text += "and the triangulation will be updated correspondingly.
"; + text += " - Find Nearest Neighbor: "; + text += "Place a query point and its nearest neighbor will be highlighted.
"; + text += " - Show Empty Sphere: "; + text += "Place a query point, locate the point in a cell "; + text += "and then show the empty sphere of that cell. "; + text += "An empty sphere of a cell is a sphere "; + text += "with all four vertices of the cell lying on it "; + text += "and no other vertices inside it.

"; + text += "Shift+Wheel to resize the trackball when it exists. "; + text += "See Mouse page for more details.

"; + + text += "Other basic features include:
"; + text += " - Randomly generate points,
"; + text += " - Read/Write files,
"; + text += " - Show vertices, Voronoi edges, Delaunay edges, and/or facets,
"; + text += " - Incremental Construct: "; + text += "Re-construct the current triangulation incrementally. "; + text += "If no triangulation exists yet, randomly generate 100 points "; + text += "and construct a Delaunay triangulation of those points.
"; + + return text; +} + +/*************************************************************/ +/* Draw functions */ + +void Viewer::draw() +{ + if( m_pScene == NULL ) return; + + QFont fontPrompt("Arial", 14); + + if( m_showAxis ) { + qglColor(::Qt::black); + drawAxis( sceneRadius() ); + } + + /* Draw vertices */ + if ( m_showVertex && m_pScene->m_dt.number_of_vertices()>0 ) { + for(QList::iterator vit = m_pScene->m_vhArray.begin(); + vit < m_pScene->m_vhArray.end(); ++vit) { + if( m_curMode == SELECT && (*vit)->isSeled() ) continue; + if( (*vit) == m_nearestNb ) continue; + drawVertex( (*vit)->point(), m_colorVertex, m_fSizeVertex ); + }//end-for-points + }//end-if-points + + /* Draw all points during incremental mode */ + if( !m_incrementalPts.isEmpty() ) { + /* draw the rest to-be-inserted vertices */ + for(QList::iterator pit=m_incrementalPts.begin(); + pit < m_incrementalPts.end(); ++pit) { + drawVertex( (*pit), ::Qt::gray, m_fSizeVertex ); + } + + switch( m_curStep ) { + case NEWPT: + /* Show prompt messages */ + qglColor( ::Qt::black ); + drawText( 10, 20, tr("Highlight the next-to-insert point"), fontPrompt ); + /* Highlight the next-to-insert point */ + drawVertex( m_curIncPt, ::Qt::red, m_fSizeVertex ); + break; + case CELL: // show the tetrahedron that contains the point + /* Show prompt messages */ + qglColor( ::Qt::black ); + drawText( 10, 20, tr("Show the tetrahedron containing the point"), fontPrompt ); + drawText( 10, 40, tr("(Only finite facets are drawn)"), fontPrompt ); + /* Highlight the next-to-insert vertex */ + drawVertex( m_curIncPt, ::Qt::red, m_fSizeVertex ); + /* Draw the cell containing that point */ + for(int i=0; i<4; ++i) { + if( m_pScene->m_dt.is_infinite(m_cellContain, i) ) continue; + drawFacet( m_pScene->m_dt.triangle( m_cellContain, i ), m_colorFacet ); + }//end-for-facets + break; + case CONFLICT: // show the conflict region + /* Show prompt messages */ + qglColor( ::Qt::black ); + drawText( 10, 20, tr("Show the conflict region"), fontPrompt ); + /* Highlight the next-to-insert vertex */ + drawVertex( m_curIncPt, ::Qt::red, m_fSizeVertex ); + /* Draw conflict region */ + for(QList::iterator fit = m_boundaryFacets.begin(); + fit < m_boundaryFacets.end(); ++fit) { + if( m_pScene->m_dt.is_infinite(*fit) ) continue; + drawFacet( m_pScene->m_dt.triangle(*fit), QColor(215, 80, 0, 96) ); //semi-transparent purple + }//end-for-facets + break; + default: + break; + }//end-of=switch + }//end-if-incpts + + /* Draw Delaunay edges */ + if( m_showDEdge ) { + for(edges_iterator eit = m_pScene->m_dt.finite_edges_begin(); + eit != m_pScene->m_dt.finite_edges_end(); ++eit) { + Segment_3 seg = m_pScene->m_dt.segment(*eit); + drawEdge( seg.vertex(0), seg.vertex(1), m_colorDEdge, m_fSizeDEdge ); + }//end-for-edges + }//end-if-dt + + /* Draw Voronoi edges */ + if( m_showVEdge ) { + for(facets_iterator fit = m_pScene->m_dt.finite_facets_begin(); + fit != m_pScene->m_dt.finite_facets_end(); ++fit) { + Object_3 o = m_pScene->m_dt.dual(*fit); + if (const Segment_3 *s = CGAL::object_cast(&o)) { + drawEdge( s->vertex(0), s->vertex(1), m_colorVEdge, m_fSizeVEdge ); + } else if (const Ray_3 *r = CGAL::object_cast(&o)) { + drawEdge( r->point(0), // the source of the ray + r->point(1), // another point on the ray, different from the source + m_colorVEdge, m_fSizeVEdge ); + } + }//end-for-edges + }//end-if-vd + + /* Draw facets */ + if( m_showFacet ) { + for(facets_iterator fit = m_pScene->m_dt.finite_facets_begin(); + fit != m_pScene->m_dt.finite_facets_end(); ++fit) { + drawFacet( m_pScene->m_dt.triangle(*fit), m_colorFacet ); + }//end-for-facets + }//end-if-facets + + /* Insert vertex mode */ + if( m_curMode == INSERT_V ) { + /* Show prompt messages */ + qglColor( ::Qt::black ); + drawText( width()-200, 20, tr("Shift+Left: Insert a vertex"), fontPrompt ); + drawText( width()-200, 40, tr("Shift+Wheel: Resize trackball"), fontPrompt ); + /* Draw the trackball */ + drawSphere( m_fRadius, m_colorTrackball ); + }//end-if-insv + + /* Insert point mode */ + else if( m_curMode == INSERT_PT ) { + /* Show prompt messages */ + qglColor( ::Qt::black ); + drawText( width()-200, 20, tr("Shift+Left: Insert a point"), fontPrompt ); + drawText( width()-200, 40, tr("Hold Left: Move the point"), fontPrompt ); + drawText( width()-200, 60, tr("Return: Insert to DT"), fontPrompt ); + drawText( width()-200, 80, tr("Escape: Cancel insertion"), fontPrompt ); + drawText( width()-200, 100, tr("Shift+Wheel: Resize trackball"), fontPrompt ); + + /* Draw the trackball */ + drawSphere( m_fRadius, m_colorTrackball ); + + if( m_hasNewPt ) { + /* Draw the newly inserted point */ + drawVertex( m_newPt, ::Qt::red, m_fSizeVertex ); + /* Draw conflict region */ + for(QList::iterator fit = m_boundaryFacets.begin(); + fit < m_boundaryFacets.end(); ++fit) { + if( m_pScene->m_dt.is_infinite(*fit) ) continue; + drawFacet( m_pScene->m_dt.triangle(*fit), QColor(215, 80, 0, 96) ); //semi-transparent purple + }//end-for-facets + }//end-if-shown + }//end-if-inspt + + /* Select mode */ + else if( m_curMode == SELECT) { + /* Show prompt messages */ + qglColor( ::Qt::black ); + drawText( width()-200, 20, tr("Shift+Left: Select"), fontPrompt ); + drawText( width()-200, 40, tr("Ctrl+Left: Add selection"), + QFont("Arial", 14) ); + drawText( width()-200, 60, tr("Escape: Cancel selection"), fontPrompt ); + drawText( width()-200, 80, tr("DEL: Delete selected"), fontPrompt ); + /* Highlight the selected vertices */ + for(QList::iterator vit=m_vidSeled.begin(); vitm_vhArray.at(*vit)->point(), ::Qt::red, m_fSizeVertex ); + }//end-for-seledpts + /* Draw the multiple selection window */ + if( m_isPress ) { + ::glDisable( GL_LIGHTING ); + startScreenCoordinatesSystem(); + qglColor( QColor(80, 180, 180, 64) ); + ::glBegin(GL_QUADS); + ::glVertex2i(m_rectSel.left(), m_rectSel.top()); + ::glVertex2i(m_rectSel.right(), m_rectSel.top()); + ::glVertex2i(m_rectSel.right(), m_rectSel.bottom()); + ::glVertex2i(m_rectSel.left(), m_rectSel.bottom()); + ::glEnd(); + stopScreenCoordinatesSystem(); + ::glEnable( GL_LIGHTING ); + }//end-if-press + }//end-if-sel + + /* Move mode */ + else if( m_curMode == MOVE ) { + /* Show prompt messages */ + qglColor( ::Qt::black ); + drawText( width()-200, 20, tr("Left Click: Select"), fontPrompt ); + + if( m_isMoving ) { + drawText( width()-200, 40, tr("Shift+Wheel: Resize trackball"), fontPrompt ); + /* Draw the trackball */ + drawSphere( m_fRadius, m_colorTrackball ); + /* Highlight the moving point */ + drawVertex( m_pScene->m_vhArray.at( m_vidMoving )->point(), ::Qt::red, m_fSizeVertex ); + }//end-if-v + }//end-if-move + + /* FindNb mode */ + else if( m_curMode == FINDNB ) { + /* Show prompt messages */ + qglColor( ::Qt::black ); + drawText( width()-200, 20, tr("Shift+Left: Place query point"), fontPrompt ); + drawText( width()-200, 40, tr("Shift+Wheel: Resize trackball"), fontPrompt ); + /* Draw the trackball */ + drawSphere( m_fRadius, m_colorTrackball ); + /* Draw the nearest neighbor */ + if( m_nearestNb != NULL ) { + drawVertex( m_queryPt, ::Qt::red, m_fSizeVertex ); + drawVertex( m_nearestNb->point(), ::Qt::red, m_fSizeVertex ); + } + }//end-if-findnb + + /* EmptySphere mode */ + else if( m_curMode == EMPTYSPH ) { + /* Show prompt messages */ + qglColor( ::Qt::black ); + drawText( width()-200, 20, tr("Shift+Left: Place query point"), fontPrompt ); + drawText( width()-200, 40, tr("Press S: Show/Hide trackball"), fontPrompt ); + drawText( width()-200, 60, tr("Shift+Wheel: Resize trackball"), fontPrompt ); + /* Draw the trackball */ + if( m_showTrackball ) + drawSphere( m_fRadius, m_colorTrackball ); + + if( m_hasEmptyS ) { + /* Draw the query point */ + drawVertex( m_queryPt, ::Qt::red, m_fSizeVertex ); + /* Draw the cell containing that point */ + for(int i=0; i<4; ++i) { + if( m_pScene->m_dt.is_infinite(m_cellContain, i) ) continue; + drawFacet( m_pScene->m_dt.triangle( m_cellContain, i ), m_colorFacet ); + }//end-for-facets + /* Draw the sphere */ + drawSphere( m_fREmptyS, m_colorEmptySphere, m_centerPt ); + } + }//end-if-emptyS +} + +void Viewer::drawVertex(const Point_3& p, const QColor& clr, float r) +{ + /* Draw regular points */ + if( m_isFlat ) { + // disable lighting + ::glDisable( GL_LIGHTING ); + + ::glPointSize(8.0); + qglColor( clr ); + + ::glBegin(GL_POINTS); + ::glVertex3f( p.x(), p.y(), p.z() ); + ::glEnd(); + + // resume lighting + ::glEnable( GL_LIGHTING ); + + return; + } + + /* Draw vertices as 3D balls */ + GLboolean lighting, colorMaterial; + ::glGetBooleanv( GL_LIGHTING, &lighting ); + ::glGetBooleanv( GL_COLOR_MATERIAL, &colorMaterial ); + ::glEnable( GL_LIGHTING ); + ::glDisable(GL_COLOR_MATERIAL); + + float color[4]; + color[0] = clr.redF(); + color[1] = clr.greenF(); + color[2] = clr.blueF(); + color[3] = clr.alphaF(); + + // move to the point + ::glPushMatrix(); + ::glTranslatef( p.x(), p.y(), p.z() ); + + // draw + GLUquadricObj* quadratic = ::gluNewQuadric(); // Create A Pointer To The Quadric Object + ::gluQuadricNormals( quadratic, GLU_SMOOTH ); // Create Smooth Normals + ::glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color ); + ::gluSphere( quadratic, r, 16, 16 ); + + // move back to origin + ::glPopMatrix(); + + if ( colorMaterial ) + ::glEnable( GL_COLOR_MATERIAL ); + if ( !lighting ) + ::glDisable( GL_LIGHTING ); +} + +void Viewer::drawEdge(const Point_3& from, const Point_3& to, const QColor& clr, float r) +{ + /* Draw regular lines */ + if( m_isFlat ) { + // disable lighting + ::glDisable( GL_LIGHTING ); + + ::glLineWidth(1.0); + qglColor( clr ); + + ::glBegin(GL_LINES); + ::glVertex3f( from.x(), from.y(), from.z() ); + ::glVertex3f( to.x(), to.y(), to.z() ); + ::glEnd(); + + // resume lighting + ::glEnable( GL_LIGHTING ); + + return; + } + + /* Draw edges as 3D cylinders */ + GLboolean lighting, colorMaterial; + ::glGetBooleanv( GL_LIGHTING, &lighting ); + ::glGetBooleanv( GL_COLOR_MATERIAL, &colorMaterial ); + ::glEnable( GL_LIGHTING ); + ::glDisable(GL_COLOR_MATERIAL); + + float color[4]; + color[0] = clr.redF(); + color[1] = clr.greenF(); + color[2] = clr.blueF(); + color[3] = clr.alphaF(); + + Vector_3 v = to - from; + + // compute the length of the edge + // method 1: +// float length = sqrt( CGAL::squared_distance( from, to ) ); + // method 2: + float length = sqrt( v.squared_length() ); + + // normalize + v = v / length; + // compute the angle: cos theta = v.z/1.0 + GLfloat angle = acos( v.z() ) / 3.1415927 * 180; + + ::glPushMatrix(); + + // move to "from" point + ::glTranslatef( from.x(), from.y(), from.z() ); + // rotate from z-axis to from-->to + // axis: cross product of z-axis and from-->to + ::glRotatef( angle, -v.y(), v.x(), 0.0f ); + // draw + GLUquadricObj* quadratic = ::gluNewQuadric(); // Create A Pointer To The Quadric Object + ::gluQuadricNormals( quadratic, GLU_SMOOTH ); // Create Smooth Normals + ::glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color ); + // gluCylinder draws a cylinder oriented along the z-axis + ::gluCylinder( quadratic, r, r, length, 16, 4 ); + + // move back to origin + ::glPopMatrix(); + + if ( colorMaterial ) + ::glEnable( GL_COLOR_MATERIAL ); + if ( !lighting ) + ::glDisable( GL_LIGHTING ); +} + +void Viewer::drawFacet(const Triangle_3& t, const QColor& clr) +{ + // disable lighting + ::glDisable( GL_LIGHTING ); + + // disable depth buffer writing + ::glDepthMask( GL_FALSE ); + + qglColor( m_colorFacet ); + + ::glBegin(GL_TRIANGLES); + Point_3 p0 = t.vertex(0); + Point_3 p1 = t.vertex(1); + Point_3 p2 = t.vertex(2); + ::glVertex3f( p0.x(), p0.y(), p0.z() ); + ::glVertex3f( p1.x(), p1.y(), p1.z() ); + ::glVertex3f( p2.x(), p2.y(), p2.z() ); + ::glEnd(); + + // resume depth buffer writing + ::glDepthMask( GL_TRUE ); + + // resume lighting + ::glEnable( GL_LIGHTING ); +} + +void Viewer::drawSphere(float r, const QColor& clr, const Point_3& center) +{ + GLboolean lighting, colorMaterial; + ::glGetBooleanv( GL_LIGHTING, &lighting ); + ::glGetBooleanv( GL_COLOR_MATERIAL, &colorMaterial ); + ::glEnable( GL_LIGHTING ); + ::glDisable(GL_COLOR_MATERIAL); + + float color[4]; + color[0] = clr.redF(); + color[1] = clr.greenF(); + color[2] = clr.blueF(); + color[3] = clr.alphaF(); + + ::glPushMatrix(); + + // move to the point + if( center != CGAL::ORIGIN ) ::glTranslatef( center.x(), center.y(), center.z() ); + + // disable depth buffer writing + ::glDepthMask( GL_FALSE ); + // draw + GLUquadricObj* quadratic = ::gluNewQuadric(); // Create A Pointer To The Quadric Object + ::gluQuadricNormals( quadratic, GLU_SMOOTH ); // Create Smooth Normals + ::glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color ); + ::gluSphere( quadratic, r, 32, 32 ); + // resume depth buffer writing + ::glDepthMask( GL_TRUE ); + + // move back to origin + ::glPopMatrix(); + + if ( colorMaterial ) + ::glEnable( GL_COLOR_MATERIAL ); + if ( !lighting ) + ::glDisable( GL_LIGHTING ); +} + +/*************************************************************/ +/* Select functions */ + +void Viewer::drawWithNames() +{ + for(int i=0; im_vhArray.size(); ++i) { + // push a name for each point onto the name stack + // note: it can NOT be used between glBegin and glEnd + ::glPushName( i ); + + // draw the point + ::glBegin(GL_POINTS); + Point_3& p = m_pScene->m_vhArray.at(i)->point(); + ::glVertex3f(p.x(), p.y(), p.z()); + ::glEnd(); + + // pop one name off the top of the name stack + ::glPopName(); + }//end-for-points + + // push a name for the newly inserted point + if( m_curMode == INSERT_PT && m_hasNewPt ) { + ::glPushName( ::GLuint(-1) ); + ::glBegin(GL_POINTS); + ::glVertex3f(m_newPt.x(), m_newPt.y(), m_newPt.z()); + ::glEnd(); + ::glPopName(); + }//end-if-newPt +} + +void Viewer::endSelection(const QPoint& point) +{ + // flush GL buffers + ::glFlush(); + + // reset GL_RENDER mode (was GL_SELECT) and get the number of selected points + size_t nSel = ::glRenderMode(GL_RENDER); + + /* No selection */ + if( nSel <= 0 ) { + if( m_curMode == SELECT ) + m_isPress = false; + }//end-if-notselected + + // each hit record has 4 data: # of names in name stack, min and max depth of old hits, + // name stack contents [see glSelectBuffer man page for more details] + // i.e. (selectBuffer())[4*i+3] is the id pushed on the stack + + /* Check whether the new point is clicked on */ + else if( m_curMode == INSERT_PT ) { + if( m_hasNewPt && (selectBuffer())[3] == ::GLuint(-1) ) + m_isMoving = true; + }//end-if-inspt + + /* Check whether vertex is clicked on */ + else if( m_curMode == MOVE ) { + m_isMoving = true; + m_vidMoving = (selectBuffer())[3]; + // compute the corresponding size of trackball, i.e. selectedV is on the ball + Point_3 p = m_pScene->m_vhArray.at( m_vidMoving )->point(); + m_fRadius = sqrt( p.x()*p.x() + p.y()*p.y() + p.z()*p.z() ); + }//end-if-move + + /* Store current selections */ + else { // m_curMode == SELECT + if( m_selMode == NORMAL ) { + // remove the old selections + for(QList::iterator vit=m_vidSeled.begin(); + vit < m_vidSeled.end(); ++vit) { + m_pScene->m_vhArray.at(*vit)->setSeled( false ); + } + m_vidSeled.clear(); + + // record the new selections + for(int i=0; im_vhArray.at( m_vidSeled.back() )->setSeled(); + } + } else { + for(int i=0; im_vhArray.at( (selectBuffer())[4*i+3] )->setSeled(); + }//end-if-contain + }//end-for + }//end-if-add + }//end-if-sel +} + +/*************************************************************/ +/* Mouse and Keyboard functions */ + +void Viewer::mousePressEvent(QMouseEvent *event) +{ + // button() holds the button that caused the event + // note: for mouse move event, button() always return Qt::NoButton + // modifiers() holds the keyboard modifier flags at the time of the event + // buttons() holds the button state when the event was generated, + // i.e. all buttons that are pressed down + // pos() holds the mouse cursor's position relative to the receiving widget + + // Get event modifiers key +#if QT_VERSION < 0x040000 + // Bug in Qt : use 0x0f00 instead of Qt::KeyButtonMask with Qt versions < 3.1 + const Qt::ButtonState modifiers = (Qt::ButtonState)(event->state() & Qt::KeyButtonMask); +#else + const Qt::KeyboardModifiers modifiers = event->modifiers(); +#endif + + if( m_curMode == INSERT_V + && event->button() == Qt::LeftButton && modifiers == Qt::SHIFT ) { + m_isPress = true; + }//end-if-insv + + else if(m_curMode == INSERT_PT && event->button() == Qt::LeftButton ) { + /* shift+left to insert */ + if( modifiers == Qt::SHIFT ) { + if( m_pScene->m_dt.is_valid() && m_pScene->m_dt.dimension() == 3 ) + m_isPress = true; + else + displayMessage( tr("There exists no triangulation yet.") ); + m_hasNewPt = false; + } else { /* left button to move */ + m_isMoving = false; + // define selection window (default was 3) + setSelectRegionWidth( 10 ); + setSelectRegionHeight( 10 ); + // perform the selection + select( event->pos() ); + if( m_isMoving ) + // redraw window + updateGL(); + else + // if no point is selected, then regular action (rotation) will be performed + QGLViewer::mousePressEvent(event); + }//end-if-shift + }//end-if-inspt + + else if( m_curMode == SELECT && event->button() == Qt::LeftButton ) { + // set the selection mode + switch( modifiers ) { + case Qt::SHIFT : // select + m_isPress = true; + m_selMode = NORMAL; + // initialize multiple selection window + m_rectSel = QRect( event->pos(), event->pos() ); + // redraw window + updateGL(); + break; + case Qt::CTRL : // add selection + m_isPress = true; + m_selMode = ADD; + // initialize multiple selection window + m_rectSel = QRect( event->pos(), event->pos() ); + // redraw window + updateGL(); + break; + default: // rotate + QGLViewer::mousePressEvent(event); + break; + } + }//end-if-select + + else if(m_curMode == MOVE && event->button() == Qt::LeftButton ) { + m_isMoving = false; + // define selection window (default was 3) + setSelectRegionWidth( 10 ); + setSelectRegionHeight( 10 ); + // perform the selection + select( event->pos() ); + if( m_isMoving ) // redraw window + updateGL(); + else // if no point is selected, then regular action (rotation) will be performed + QGLViewer::mousePressEvent(event); + }//end-if-move + + else if( m_curMode == FINDNB + && event->button() == Qt::LeftButton && modifiers == Qt::SHIFT ) { + if( m_pScene->m_dt.is_valid() && m_pScene->m_dt.dimension() == 3 ) + m_isPress = true; + else + displayMessage( tr("There exists no triangulation yet.") ); + }//end-if-findnb + + else if( m_curMode == EMPTYSPH + && event->button() == Qt::LeftButton && modifiers == Qt::SHIFT ) { + if( m_pScene->m_dt.is_valid() && m_pScene->m_dt.dimension() == 3 ) + m_isPress = true; + else + displayMessage( tr("There exists no triangulation yet.") ); + m_hasEmptyS = false; + }//end-if-emptyS + + else + QGLViewer::mousePressEvent(event); +} + +void Viewer::mouseMoveEvent(QMouseEvent *event) +{ + if( m_curMode == INSERT_PT && m_isMoving ) { + Vec pt; + if( computeIntersect( event->pos(), pt ) ) { + m_newPt = Point_3(pt.x, pt.y, pt.z); + // compute the conflict hole induced by point p + computeConflict( m_newPt ); + }//end-if-compute + + // redraw + updateGL(); + }//end-if-inspt + + else if( m_curMode == SELECT && m_isPress ) { + // update multiple selection window + m_rectSel.setBottomRight( event->pos() ); + // redraw + updateGL(); + }//end-if-sel + + else if( m_curMode == MOVE && m_isMoving ) { + Vec pt; + if( computeIntersect( event->pos(), pt ) ) { + // note: QList::operator[] return a modifiable reference; + // while QList::at return a const reference +#if CGAL_VERSION_NR < 1030700000 + // move_point moves the point stored in v to p while preserving the Delaunay property + // it calls remove(v) followed by insert(p) and return the new handle + // it supposely faster when the point has not moved much + m_pScene->m_vhArray[m_vidMoving] = m_pScene->m_dt.move_if_no_collision( + m_pScene->m_vhArray.at( m_vidMoving ), + Point_3( pt.x, pt.y, pt.z ) ); +#else + // move_if_no_collision moves the point stored in v to pt + // if there is not already another vertex placed on pt, + // the triangulation is modified s.t. the new position of v is pt; + // otherwise, the vertex at point pt is returned. + Vertex_handle vh = m_pScene->m_dt.move_if_no_collision( + m_pScene->m_vhArray.at( m_vidMoving ), + Point_3( pt.x, pt.y, pt.z ) ); + int id1 = m_pScene->m_vhArray.indexOf( vh ); + int id2 = m_pScene->m_vhArray.indexOf( vh, m_vidMoving+1 ); + // remove the duplicate in vhArray + if( id1 != m_vidMoving ) + m_pScene->m_vhArray.removeAt( id1 ); + else if( id2 != -1 ) + m_pScene->m_vhArray.removeAt( id2 ); + m_pScene->m_vhArray[m_vidMoving] = vh; +#endif + }//end-if-compute + + // redraw + updateGL(); + }//end-if-move + + else + QGLViewer::mouseMoveEvent(event); +} + +void Viewer::mouseReleaseEvent(QMouseEvent *event) +{ + /* INS_V mode - Shift+Left: compute and insert a vertex */ + if( m_curMode == INSERT_V && m_isPress ) { + m_isPress = false; + Vec pt; + if( computeIntersect( event->pos(), pt ) ) { + m_pScene->m_vhArray.push_back( m_pScene->m_dt.insert( Point_3( pt.x, pt.y, pt.z ) ) ); + }//end-if-compute + + // redraw + updateGL(); + }//end-if-ins + + /* INS_PT mode - Shift+Left: compute and insert a point */ + else if( m_curMode == INSERT_PT && m_isPress ) { + m_isPress = false; + Vec pt; + if( computeIntersect( event->pos(), pt ) ) { + m_hasNewPt = true; + m_newPt = Point_3(pt.x, pt.y, pt.z); + // compute the conflict hole induced by point p + computeConflict( m_newPt ); + }//end-if-compute + + // redraw + updateGL(); + }//end-if-inspt + + /* INS_PT mode - Left: compute and insert a point */ + else if( m_curMode == INSERT_PT && m_isMoving ) { + m_isMoving = false; + Vec pt; + if( computeIntersect( event->pos(), pt ) ) { + m_newPt = Point_3(pt.x, pt.y, pt.z); + // compute the conflict hole induced by point p + computeConflict( m_newPt ); + }//end-if-compute + + // redraw + updateGL(); + }//end-if-inspt + + /* SEL mode - Left: terminate multiple point selection */ + else if( m_curMode == SELECT && m_isPress ) { + // might swap left/right and top/bottom to make rectanle valid +#if QT_VERSION < 0x040000 + m_rectSel = m_rectSel.normalize(); +#else + m_rectSel = m_rectSel.normalized(); +#endif + + if( m_rectSel.width() == 1 && m_rectSel.height() == 1 ) { /* select a point */ + // set a default selection window + setSelectRegionWidth( 10 ); + setSelectRegionHeight( 10 ); + // compute rectangle center and perform selection + select( m_rectSel.center() ); + if( m_isPress ) { + m_isPress = false; + } else { + displayMessage( tr("No point is selected.") ); + } + } else { /* select multiple points, ie. selection window > 1 */ + // define selection window + if( m_rectSel.width() < 10 ) + setSelectRegionWidth( 10 ); + else + setSelectRegionWidth( m_rectSel.width() ); + if( m_rectSel.height() < 10 ) + setSelectRegionHeight( 10 ); + else + setSelectRegionHeight( m_rectSel.height() ); + // compute rectangle center and perform selection + select( m_rectSel.center() ); + if( m_isPress ) { + m_isPress = false; + displayMessage( QString::number(m_vidSeled.size()) + tr(" points are selected") ); + } else { // empty window will cancel the current selection + for(QList::iterator iit = m_vidSeled.begin(); iit < m_vidSeled.end(); ++iit) + m_pScene->m_vhArray.at(*iit)->setSeled( false ); + m_vidSeled.clear(); + } + }//end-if-selwindow + + // update display to show + updateGL(); + }//end-if-select + + /* MOVE mode - Left: terminate point moving */ + else if( m_curMode == MOVE && m_isMoving ) { + Vec pt; + if( computeIntersect( event->pos(), pt ) ) { + // note: QList::operator[] return a modifiable reference; + // while QList::at return a const reference +#if CGAL_VERSION_NR < 1030700000 + // move_point moves the point stored in v to p while preserving the Delaunay property + // it calls remove(v) followed by insert(p) and return the new handle + // it supposely faster when the point has not moved much + m_pScene->m_vhArray[m_vidMoving] = m_pScene->m_dt.move_if_no_collision( + m_pScene->m_vhArray.at( m_vidMoving ), + Point_3( pt.x, pt.y, pt.z ) ); +#else + // move_if_no_collision moves the point stored in v to pt + // if there is not already another vertex placed on pt, + // the triangulation is modified s.t. the new position of v is pt; + // otherwise, the vertex at point pt is returned. + Vertex_handle vh = m_pScene->m_dt.move_if_no_collision( + m_pScene->m_vhArray.at( m_vidMoving ), + Point_3( pt.x, pt.y, pt.z ) ); + int id1 = m_pScene->m_vhArray.indexOf( vh ); + int id2 = m_pScene->m_vhArray.indexOf( vh, m_vidMoving+1 ); + // remove the duplicate in vhArray + if( id1 != m_vidMoving ) + m_pScene->m_vhArray.removeAt( id1 ); + else if( id2 != -1 ) + m_pScene->m_vhArray.removeAt( id2 ); + m_pScene->m_vhArray[m_vidMoving] = vh; +#endif + }//end-if-compute + + // redraw + updateGL(); + }//end-if-move + + /* FindNb mode - Shift+Left: find the nearest neighbor of the point */ + else if( m_curMode == FINDNB && m_isPress ) { + m_isPress = false; + Vec pt; + if( computeIntersect( event->pos(), pt ) ) { + m_queryPt = Point_3( pt.x, pt.y, pt.z ); + m_nearestNb = m_pScene->m_dt.nearest_vertex( m_queryPt ); + }//end-if-compute + + // redraw + updateGL(); + }//end-if-findnb + + /* EmptySphere mode - Shift+Left: show the empty sphere of the cell */ + else if( m_curMode == EMPTYSPH && m_isPress ) { + m_isPress = false; + Vec pt; + m_hasEmptyS = computeIntersect( event->pos(), pt ); + if( m_hasEmptyS ) { + m_queryPt = Point_3( pt.x, pt.y, pt.z ); + // find the cell that contains point p in its interior + m_cellContain = m_pScene->m_dt.locate( m_queryPt ); + // show error if point is outside the convex hull + if( m_pScene->m_dt.is_infinite( m_cellContain ) ) { + m_hasEmptyS = false; + displayMessage( tr("Query point is outside the convex hull!") ); + } else { /* compute the empty sphere */ + // find the circumcenter of the four vertices of c + m_centerPt = m_pScene->m_dt.dual( m_cellContain ); + // compute the radius of the empty sphere + m_fREmptyS = sqrt( CGAL::squared_distance( m_centerPt, + m_cellContain->vertex(0)->point() ) ); + } + }//end-if-compute + // redraw + updateGL(); + }//end-if-emptysphere + + else + QGLViewer::mouseReleaseEvent(event); +} + +void Viewer::wheelEvent(QWheelEvent *event) +{ + // Get event modifiers key +#if QT_VERSION < 0x040000 + // Bug in Qt : use 0x0f00 instead of Qt::KeyButtonMask with Qt versions < 3.1 + const Qt::ButtonState modifiers = (Qt::ButtonState)(event->state() & Qt::KeyButtonMask); +#else + const Qt::KeyboardModifiers modifiers = event->modifiers(); +#endif + + if( (m_curMode == INSERT_V || m_curMode == FINDNB || m_curMode == EMPTYSPH ) + && modifiers == Qt::SHIFT ) { + // delta() returns the distance that the wheel is rotated, in eighths of a degree. + // note: most mouse types work in steps of 15 degrees + // positive value: rotate forwards away from the user; + // negative value: rotate backwards toward the user. + m_fRadius += (event->delta()*1. / m_iStep ); // inc-/decrease by 0.1 per step + if( m_fRadius < 0.1 ) + m_fRadius = 0.1; + + // redraw + updateGL(); + }//end-if-insv + + else if( m_curMode == INSERT_PT && modifiers == Qt::SHIFT ) { + // delta() returns the distance that the wheel is rotated, in eighths of a degree. + // note: most mouse types work in steps of 15 degrees + // positive value: rotate forwards away from the user; + // negative value: rotate backwards toward the user. + float origR = m_fRadius; + m_fRadius += (event->delta()*1. / m_iStep ); // inc-/decrease by 0.1 per step + if( m_fRadius < 0.1 ) + m_fRadius = 0.1; + // update the new point and its conflict region + if( m_hasNewPt ) { + origR = m_fRadius / origR; + m_newPt = Point_3( m_newPt.x()*origR, m_newPt.y()*origR, m_newPt.z()*origR ); + // compute the conflict hole induced by point p + computeConflict( m_newPt ); + }//end-if-conflict + + // redraw + updateGL(); + }//end-if-inspt + + // resize the trackball when moving a point + else if( m_curMode == MOVE && modifiers == Qt::SHIFT && m_isMoving ) { + float origR = m_fRadius; + m_fRadius += (event->delta()*1. / m_iStep ); // inc-/decrease by 0.1 per step + if( m_fRadius < 0.1 ) + m_fRadius = 0.1; + origR = m_fRadius / origR; + Point_3 pt = m_pScene->m_vhArray.at( m_vidMoving )->point(); + // note: QList::operator[] return a modifiable reference; + // while QList::at return a const reference +#if CGAL_VERSION_NR < 1030700000 + // move_point moves the point stored in v to p while preserving the Delaunay property + // it calls remove(v) followed by insert(p) and return the new handle + // it supposely faster when the point has not moved much + m_pScene->m_vhArray[m_vidMoving] = m_pScene->m_dt.move_if_no_collision( + m_pScene->m_vhArray.at( m_vidMoving ), + Point_3( pt.x()*origR, pt.y()*origR, pt.z()*origR ) ); +#else + // move_if_no_collision moves the point stored in v to pt + // if there is not already another vertex placed on pt, + // the triangulation is modified s.t. the new position of v is pt; + // otherwise, the vertex at point pt is returned. + Vertex_handle vh = m_pScene->m_dt.move_if_no_collision( + m_pScene->m_vhArray.at( m_vidMoving ), + Point_3( pt.x()*origR, pt.y()*origR, pt.z()*origR ) ); + int id1 = m_pScene->m_vhArray.indexOf( vh ); + int id2 = m_pScene->m_vhArray.indexOf( vh, m_vidMoving+1 ); + // remove the duplicate in vhArray + if( id1 != m_vidMoving ) + m_pScene->m_vhArray.removeAt( id1 ); + else if( id2 != -1 ) + m_pScene->m_vhArray.removeAt( id2 ); + m_pScene->m_vhArray[m_vidMoving] = vh; +#endif + + // redraw + updateGL(); + }//end-if-move + + else + QGLViewer::wheelEvent(event); +} + +void Viewer::keyPressEvent(QKeyEvent *event) +{ + // Get event modifiers key +#if QT_VERSION < 0x040000 + // Bug in Qt : use 0x0f00 instead of Qt::KeyButtonMask with Qt versions < 3.1 + const Qt::ButtonState modifiers = (Qt::ButtonState)(event->state() & Qt::KeyButtonMask); +#else + const Qt::KeyboardModifiers modifiers = event->modifiers(); +#endif + + /* Insert the newly inserted point as a vertex */ + if( m_curMode == INSERT_PT && m_hasNewPt + && ( event->key()==Qt::Key_Return || event->key()==Qt::Key_Enter ) + && modifiers==Qt::NoButton ) { + Facet& f = m_boundaryFacets.first(); // a boundary facet, i.e. a pair (cell_handle, i) + // insert_in_hole will create a new vertex by starring a hole + // i.e. delete all conflict cells, create a new vertex, + // and for each boundary facet, create a new cell with the new vertex + // it takes in an iterator range of conflict cells which specifies a hole + // and (begin, i) is a boundary facet that begin is one of the conflict cell + // but begin->neighbor(i) is not + // it returns the handle of the new vertex + m_pScene->m_vhArray.push_back( m_pScene->m_dt.insert_in_hole( m_newPt, // the point + m_conflictCells.begin(), // cell_begin + m_conflictCells.end(), // cell_end + f.first, // cell_handle begin + f.second ) ); // integer i + + m_hasNewPt = false; + // erase old conflict hole info + m_boundaryFacets.clear(); + m_conflictCells.clear(); + + // redraw + updateGL(); + }//end-if-insVertex + + /* Cancel the newly inserted point and its conflict region */ + else if( m_curMode == INSERT_PT && m_hasNewPt + && event->key()==Qt::Key_Escape && modifiers==Qt::NoButton ) { + m_hasNewPt = false; + // erase old conflict hole info + m_boundaryFacets.clear(); + m_conflictCells.clear(); + + // redraw + updateGL(); + }//end-if-escapeIns + + /* Delete selected points */ + else if( m_curMode == SELECT + && event->key()==Qt::Key_Delete && modifiers==Qt::NoButton ) { + // sort selected id's in descending order + qSort(m_vidSeled.begin(), m_vidSeled.end(), qGreater()); + for(QList::iterator vit=m_vidSeled.begin(); vitm_dt.remove( m_pScene->m_vhArray.takeAt( *vit ) ); + } + // clear the selection buffer + m_vidSeled.clear(); + + // redraw + updateGL(); + }//end-if-del + + /* Cancel the selection */ + else if( m_curMode == SELECT + && event->key()==Qt::Key_Escape && modifiers==Qt::NoButton ) { + // clear the selection buffer + for(QList::iterator iit=m_vidSeled.begin(); iitm_vhArray.at(*iit)->setSeled( false ); + } + m_vidSeled.clear(); + + // redraw + updateGL(); + }//end-if-escapeSel + + + /* Show/hide the trackball when drawing the empty sphere */ + else if( m_curMode == EMPTYSPH + && event->key()==Qt::Key_S && modifiers==Qt::NoButton ) { + m_showTrackball = !m_showTrackball; + // redraw + updateGL(); + }//end-if-showBall + + else + QGLViewer::keyPressEvent(event); +} + +/*************************************************************/ +/* Computation functions */ + +bool Viewer::computeIntersect( const QPoint & pos, Vec & pt ) +{ + Vec eye, dir; + // Compute eye position and direction to the clicked point, + // used to draw a representation of the intersecting line + camera()->convertClickToLine( pos, eye, dir ); + // Compute the intersection point with the sphere + // note that the center of the sphere is at the origin (0, 0, 0) + // thus, (1) pt = eye + t*dir and (2) dist( pt, origin ) = radius + // i.e. (x_eye + t*x_dir)^2 + (y_eye + t*y_dir)^2 + (z_eye + t*z_dir)^2 = r^2 + // --> t^2( dir*dir ) + 2t( eye*dir ) + eye*eye - r^2 = 0 + // where "dir*dir" is the dot product of vector dir + // we need to solve t and the smaller t (nearer to eye position) is what we want + float a = dir*dir; + float b = eye*dir; + float c = eye*eye - m_fRadius*m_fRadius; + float delta = b*b - a*c; + if( delta < 0 ) { + displayMessage( tr("Point is not on the sphere!") ); + return false; + } else { + float t = ( (-1.)*b - sqrt(delta) ) / a; + pt = eye + t*dir; + return true; + } +} + +void Viewer::computeConflict( Point_3 pt ) +{ + // find the cell that contains point p in its interior + m_cellContain = m_pScene->m_dt.locate( pt ); + // erase old conflict hole info + m_boundaryFacets.clear(); + m_conflictCells.clear(); + // show msg if point is outside the convex hull + if( m_pScene->m_dt.is_infinite( m_cellContain ) ) + displayMessage( tr("Note: point is outside the convex hull.") ); + // compute the conflict hole induced by point p + m_pScene->m_dt.find_conflicts( pt, // the point + m_cellContain, // starting cell that must be in conflict + std::back_inserter(m_boundaryFacets), // the facets on the boundary + std::back_inserter(m_conflictCells) ); // the cells in conflict +} + +/*************************************************************/ +/* Animation functions */ + +void Viewer::toggleIncremental(bool on) { + if( on ) { // play + if( m_incrementalPts.isEmpty() ) { + /* start play */ + if( m_pScene->m_dt.number_of_vertices() == 0 ) { + CGAL::Random_points_in_cube_3 pts_generator(1.0); + CGAL::copy_n( pts_generator, 100, std::back_inserter(m_incrementalPts) ); + } else { + for(QList::iterator vit = m_pScene->m_vhArray.begin(); + vit < m_pScene->m_vhArray.end(); ++vit) { + m_incrementalPts.push_back( (*vit)->point() ); + }//end-for + // erase existing vertices + initClean(); + }//end-if-pts + // sorts points in a way that improves space locality + CGAL::spatial_sort( m_incrementalPts.begin(), m_incrementalPts.end() ); + // set the current to "hightlight the new point" + m_curStep = INIT; + }/* else resume play */ + + // set up the timer + m_pTimer->start(1000); + } else { // pause + m_pTimer->stop(); + } + + // redraw + updateGL(); +} + +void Viewer::stopIncremental() { + if( !m_incrementalPts.isEmpty() ) { + // will call toggleIncremental to stop the timer + emit( stopIncAnimation() ); + + // insert the rest points + for(QList::iterator pit=m_incrementalPts.begin(); + pit < m_incrementalPts.end(); ++pit) { + Vertex_handle hint; + if( m_pScene->m_vhArray.isEmpty() ) { + hint = m_pScene->m_dt.insert( *pit ); + } else { + hint = m_pScene->m_vhArray.last(); + hint = m_pScene->m_dt.insert( *pit, hint ); + } + m_pScene->m_vhArray.push_back( hint ); + } + m_incrementalPts.clear(); + } + + // redraw + updateGL(); +} + +void Viewer::incremental_insert() { + Vertex_handle hint; + if( !m_incrementalPts.isEmpty() ) { + switch( m_curStep ) { + case INIT: // end of INIT: get the next-to-insert point + m_curIncPt = m_incrementalPts.at(0); + m_curStep = NEWPT; + break; + case NEWPT: // end of NEWPT: locate the cell containing the point + if( m_pScene->m_dt.is_valid() && m_pScene->m_dt.dimension() == 3 ) { + computeConflict( m_curIncPt ); + m_curStep = CELL; + } + else { + // popup the first point and insert it + m_curIncPt = m_incrementalPts.takeFirst(); + if( m_pScene->m_vhArray.isEmpty() ) { + hint = m_pScene->m_dt.insert( m_curIncPt ); + } + else { + hint = m_pScene->m_vhArray.last(); + hint = m_pScene->m_dt.insert( m_curIncPt, hint ); + } + m_pScene->m_vhArray.push_back( hint ); + m_curStep = INIT; + } + break; + case CELL: // end of CELL: compute the conflict region + m_curStep = CONFLICT; + break; + case CONFLICT: // end of CONFLICT: do the insertion and go back to INIT + // popup the first point and insert it + m_curIncPt = m_incrementalPts.takeFirst(); + if( m_pScene->m_vhArray.isEmpty() ) { + hint = m_pScene->m_dt.insert( m_curIncPt ); + } else { + hint = m_pScene->m_vhArray.last(); + hint = m_pScene->m_dt.insert( m_curIncPt, hint ); + } + m_pScene->m_vhArray.push_back( hint ); + m_curStep = INIT; + break; + }//end-of-switch + } else { + /* if finished, then start over */ + for(QList::iterator vit = m_pScene->m_vhArray.begin(); + vit < m_pScene->m_vhArray.end(); ++vit) { + m_incrementalPts.push_back( (*vit)->point() ); + }//end-for + // erase existing vertices + initClean(); + // set the current to "hightlight the new point" + m_curStep = INIT; + } + + // redraw + updateGL(); +} diff --git a/Triangulation_3/demo/Triangulation_3/Viewer.h b/Triangulation_3/demo/Triangulation_3/Viewer.h new file mode 100644 index 00000000000..ddf9151d646 --- /dev/null +++ b/Triangulation_3/demo/Triangulation_3/Viewer.h @@ -0,0 +1,290 @@ +#ifndef VIEWER_H +#define VIEWER_H + +#include "Scene.h" +#include +#include +#include +#include +#include "PreferenceDlg.h" + +#include +using namespace qglviewer; + +class MainWindow; + +class Viewer : public QGLViewer { + + Q_OBJECT + +public: + Viewer(QWidget* parent) + : QGLViewer(parent) + , m_showAxis(false) + , m_showVertex(true) + , m_showDEdge(true) + , m_showVEdge(false) + , m_showFacet(false) + , m_isFlat(false) + , m_fRadius(1.) + , m_curMode(NONE) + , m_selMode(NORMAL) + , m_isPress(false) + , m_isMoving(false) + , m_hasNewPt(false) + , m_nearestNb(NULL) + , m_hasEmptyS(false) + , m_showTrackball(true) + , m_pDlgPrefer(NULL) + {} + + enum Mode { NONE, INSERT_V, INSERT_PT, MOVE, SELECT, FINDNB, EMPTYSPH }; + +public: + inline void setScene(Scene* pScene) { m_pScene = pScene; } + + // set current mode + inline void setMode(Mode m) { + m_curMode = m; + m_isMoving = false; + m_hasEmptyS = false; + m_nearestNb = NULL; + updateGL(); + } + + // set selectBuffer size (if necessary) + inline void setSelBuffSize() { + // Default selectBuffer size is 4000 + // (i.e. 1000 objects in selection region, since each object pushes 4 values). + if( m_pScene->m_vhArray.size() > 900 ) + // The previous selectBuffer is deleted and a new one is created. + setSelectBufferSize( 4*(m_pScene->m_vhArray.size() + 100) ); + } + + void readSettings() { + // read from an .ini file + QSettings settings("settings.ini", QSettings::IniFormat); + // QVariant value ( const QString & key, const QVariant & defaultValue = QVariant() ) + // Because QVariant is part of the QtCore library, + // it cannot provide conversion functions to data types such as QColor and QImage, + // which are part of QtGui. + // In other words, there is no toColor(), toImage(), or toPixmap() functions in QVariant. + // Instead, use the QVariant::value() or the qVariantValue() template function + m_colorVertex = settings.value( "Show/vertexcolor", QColor(255, 150, 0) ).value(); +#if QT_VERSION >= 0x040600 + m_fSizeVertex = settings.value( "Show/vertexsize", 0.04f ).toFloat(); +#else + m_fSizeVertex = settings.value( "Show/vertexsize", 0.04f ).value(); +#endif + m_colorDEdge = settings.value( "Show/dedgecolor", QColor(0, 255, 0) ).value(); +#if QT_VERSION >= 0x040600 + m_fSizeDEdge = settings.value( "Show/dedgesize", 0.01f ).toFloat(); +#else + m_fSizeDEdge = settings.value( "Show/dedgesize", 0.01f ).value(); +#endif + m_colorVEdge = settings.value( "Show/vedgecolor", QColor(0, 0, 255) ).value(); +#if QT_VERSION >= 0x040600 + m_fSizeVEdge = settings.value( "Show/vedgesize", 0.01f ).toFloat(); +#else + m_fSizeVEdge = settings.value( "Show/vedgesize", 0.01f ).value(); +#endif + m_colorFacet = settings.value( "Show/facetcolor", + QColor(255, 255, 0, 96) ).value(); + m_colorTrackball = settings.value( "Show/ballcolor", + QColor(150, 150, 150, 128) ).value(); + m_iStep = settings.value( "Show/ballstep", 4000 ).toInt(); + m_colorEmptySphere = settings.value( "Show/spherecolor", + QColor(180, 50, 180, 64) ).value(); + } + + void writeSettings() { + // write to an .ini file + QSettings settings("settings.ini", QSettings::IniFormat); + // The inverse conversion (e.g., from QColor to QVariant) is automatic + // for all data types supported by QVariant, including GUI-related types + settings.setValue("Show/vertexcolor", m_colorVertex); + settings.setValue("Show/vertexsize", m_fSizeVertex); + settings.setValue("Show/dedgecolor", m_colorDEdge); + settings.setValue("Show/dedgesize", m_fSizeDEdge); + settings.setValue("Show/vedgecolor", m_colorVEdge); + settings.setValue("Show/vedgesize", m_fSizeVEdge); + settings.setValue("Show/facetcolor", m_colorFacet); + settings.setValue("Show/ballcolor", m_colorTrackball); + settings.setValue("Show/ballstep", m_iStep); + settings.setValue("Show/spherecolor", m_colorEmptySphere); + } + +public slots : + // clear scene + void clear() { + m_pScene->eraseOldData(); + m_hasNewPt = false; + m_boundaryFacets.clear(); + m_conflictCells.clear(); + m_vidSeled.clear(); + m_isMoving = false; + m_nearestNb = NULL; + m_hasEmptyS = false; + if( !m_incrementalPts.isEmpty() ) { + emit( stopIncAnimation() ); + m_incrementalPts.clear(); + } + } + + // play/pause incremental construction + void toggleIncremental(bool on); + // clean up old data and information + void initClean() { + m_pScene->eraseOldData(); + m_hasNewPt = false; + m_boundaryFacets.clear(); + m_conflictCells.clear(); + m_vidSeled.clear(); + m_isMoving = false; + m_nearestNb = NULL; + m_hasEmptyS = false; + } + // stop incremental construction + void stopIncremental(); + // incremental insert a vertex (invoked by Timer) + void incremental_insert(); + + // show options + inline void toggleShowAxis(bool flag) { m_showAxis = flag; updateGL(); } + inline void toggleShowVertex(bool flag) { m_showVertex = flag; updateGL(); } + inline void toggleShowDEdge(bool flag) { m_showDEdge = flag; updateGL(); } + inline void toggleShowVEdge(bool flag) { m_showVEdge = flag; updateGL(); } + inline void toggleShowFacet(bool flag) { m_showFacet = flag; updateGL(); } + inline void toggleFlat(bool flag) { m_isFlat = flag; updateGL(); } + + // set preferences + void setPreferences() { + if (!m_pDlgPrefer) { + m_pDlgPrefer = new PreferenceDlg(this); + m_pDlgPrefer->init( m_colorVertex, m_fSizeVertex, m_colorDEdge, m_fSizeDEdge, m_colorVEdge, m_fSizeVEdge, + m_colorFacet, m_colorTrackball, m_colorEmptySphere, m_iStep/40 ); // 5*8, 5 degrees of wheel + connect(m_pDlgPrefer, SIGNAL(applyChanges()), this, SLOT(acceptChanges()) ); + } + m_pDlgPrefer->show(); + m_pDlgPrefer->raise(); + m_pDlgPrefer->activateWindow(); + } + + void acceptChanges() { + m_colorVertex = m_pDlgPrefer->m_colorVertex; + m_fSizeVertex = m_pDlgPrefer->m_fSizeVertex; + m_colorDEdge = m_pDlgPrefer->m_colorDEdge; + m_fSizeDEdge = m_pDlgPrefer->m_fSizeDEdge; + m_colorVEdge = m_pDlgPrefer->m_colorVEdge; + m_fSizeVEdge = m_pDlgPrefer->m_fSizeVEdge; + m_colorFacet = m_pDlgPrefer->m_colorFacet; + m_colorTrackball = m_pDlgPrefer->m_colorTrackball; + m_iStep = m_pDlgPrefer->m_iStep*40; + m_colorEmptySphere = m_pDlgPrefer->m_colorEmptySphere; + // redraw + updateGL(); + } + + signals: + void stopIncAnimation(); + +// overloading QGLViewer virtual functions +protected: + // initialize Viewer OpenGL context + // Note: the default implement is empty and this is overloading. + void init(); + // draw points, segments, and polygons + void draw(); + + // customize selection process + void drawWithNames(); + void endSelection(const QPoint& point); + // customize mouse events + void mousePressEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + void wheelEvent(QWheelEvent *event); + // customize key events + void keyPressEvent(QKeyEvent *event); + + // customize help message + QString helpString() const; + +private: + // draw a 3d effect vertex + void drawVertex(const Point_3& p, const QColor& clr, float r); + // draw a 3d effect edge + void drawEdge(const Point_3& from, const Point_3& to, const QColor& clr, float r); + // draw a facet + void drawFacet(const Triangle_3& t, const QColor& clr); + // draw a sphere with/without Axis + void drawSphere(float r, const QColor& clr, const Point_3& center=CGAL::ORIGIN); + + // test whether the give 3D point is on the sphere + inline bool isOnSphere( const Point_3 & pt ) { + return ( (pt.x()*pt.x() + pt.y()*pt.y() + pt.z()*pt.z()) == (m_fRadius*m_fRadius) ); + } + + // compute the intersection point with the sphere + bool computeIntersect( const QPoint & pos, Vec & pt ); + // compute the conflict region + void computeConflict( Point_3 pt ); + +private: + Scene* m_pScene; + // play timer + QTimer* m_pTimer; + Point_3 m_curIncPt; + QList m_incrementalPts; + enum Step { INIT, NEWPT, CELL, CONFLICT }; + Step m_curStep; + Cell_handle m_cellContain; + QList m_boundaryFacets; + QList m_conflictCells; + // show options + bool m_showAxis; + bool m_showVertex; + bool m_showDEdge; + bool m_showVEdge; + bool m_showFacet; + bool m_isFlat; + // trackball + float m_fRadius; + // mode + Mode m_curMode; + bool m_isPress; + bool m_isMoving; + // insert point + bool m_hasNewPt; + Point_3 m_newPt; + // select vertex + enum selectionMode { NORMAL, ADD }; + selectionMode m_selMode; + QRect m_rectSel; + QList m_vidSeled; + // move vertex/point + int m_vidMoving; + // nearest neighbor + Point_3 m_queryPt; + Vertex_handle m_nearestNb; + // empty sphere + bool m_hasEmptyS; + bool m_showTrackball; + Point_3 m_centerPt; + float m_fREmptyS; + // change colors + PreferenceDlg* m_pDlgPrefer; + float m_fSizeVertex; + float m_fSizeDEdge; + float m_fSizeVEdge; + QColor m_colorVertex; + QColor m_colorDEdge; + QColor m_colorVEdge; + QColor m_colorFacet; + QColor m_colorTrackball; + QColor m_colorEmptySphere; + // trackball resizing fineness + int m_iStep; +}; + +#endif diff --git a/Triangulation_3/demo/Triangulation_3/documentation/about.html b/Triangulation_3/demo/Triangulation_3/documentation/about.html new file mode 100644 index 00000000000..4149acaf9d5 --- /dev/null +++ b/Triangulation_3/demo/Triangulation_3/documentation/about.html @@ -0,0 +1,13 @@ + + +

CGAL Triangulation_3 Demo

+

Copyright ©2010-2011
+ INRIA Sophia Antipolis - Mediterranee

+

This application illustrates an interactive demo for 3D Delaunay Triangulation package + of CGAL.

+

See also the package manual:
+ + 3D Triangulations +

+ + diff --git a/Triangulation_3/demo/Triangulation_3/documentation/about_CGAL.html b/Triangulation_3/demo/Triangulation_3/documentation/about_CGAL.html new file mode 100644 index 00000000000..b8a610ce41e --- /dev/null +++ b/Triangulation_3/demo/Triangulation_3/documentation/about_CGAL.html @@ -0,0 +1,7 @@ + + +

Computational Geometry Algorithms Library

+

CGAL provides efficient and reliable geometric algorithms in the form of a C++ library.

+

For more information visit www.cgal.org.

+ + diff --git a/Triangulation_3/demo/Triangulation_3/icons/about_CGAL.html b/Triangulation_3/demo/Triangulation_3/icons/about_CGAL.html new file mode 100644 index 00000000000..d87503a3469 --- /dev/null +++ b/Triangulation_3/demo/Triangulation_3/icons/about_CGAL.html @@ -0,0 +1,8 @@ + + +

+

Computational Geometry Algorithms Library

+

CGAL provides efficient and reliable geometric algorithms in the form of a C++ library.

+

For more information visit www.cgal.org

+ + diff --git a/Triangulation_3/demo/Triangulation_3/icons/cgal_logo.xpm b/Triangulation_3/demo/Triangulation_3/icons/cgal_logo.xpm new file mode 100644 index 00000000000..6a69b3d67e1 --- /dev/null +++ b/Triangulation_3/demo/Triangulation_3/icons/cgal_logo.xpm @@ -0,0 +1,24 @@ +/* XPM */ +const char * demoicon_xpm[] = { +/* columns rows colors chars-per-pixel */ +"16 16 3 1", +" c None", +". c #FFFF00", +"+ c #000000", +/* pixels */ +"................", +"...++++...++++..", +"..+....+.+....+.", +"..+......+......", +"..+......+..+++.", +"..+......+....+.", +"..+....+.+....+.", +"...++++...++++..", +"................", +"...++++...+.....", +"..+....+..+.....", +"..+....+..+.....", +"..++++++..+.....", +"..+....+..+.....", +"..+....+..+++++.", +"................"}; diff --git a/Triangulation_3/demo/Triangulation_3/icons/clear.jpeg b/Triangulation_3/demo/Triangulation_3/icons/clear.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..ab3a8f653ac847a600c4c2d48bb089c969c50f83 GIT binary patch literal 843 zcmex=EH?MF3WI7B-NSo&Wa-+N*chO`69!SIV4|M zr%4RT%RHEWe_irNdY#YrdwkCxMJ}AO>BwcF2!lJNDm@KlCl5-Ot~>SVn)K~R-F4!# zG{t%BWqZ9#dF=x)m+t3fGQOkDsWdS>{otwnXY#C@LwEM4n&~cn{Z6l;ua)0uqpNy* zBxf~`RCjb#Me7lbPkre%JuA)~d4D0et2Auw>N|U!jix>m33M%)*y^?8cgK2*=+J0s zg-hp)1t!G$S$42?9FP~3_`;mq8=9H6HsA;=SRL&8uV)Pj#N$ zIw42moARBy_LpAM>gp9NawZtxsqamg<#R%^fIB5|m)xstqq$L6HW)m<(R(7f{`PgL zuhz3P*`}^3TE2OQ&WYV()?4a&?^ONyefdhsMCN0sP90X9@DwFL|C#lw+ggI9lV(Rptg$$GHa02ode5%7`ow#O Jo}c-D69A$GHiG~F literal 0 HcmV?d00001 diff --git a/Triangulation_3/demo/Triangulation_3/icons/coordinates.jpeg b/Triangulation_3/demo/Triangulation_3/icons/coordinates.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..184203abe49b86be3deaad82d33d2a7587c827d5 GIT binary patch literal 1268 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 IM6N<$f-Pt`I{*Lx literal 0 HcmV?d00001 diff --git a/Triangulation_3/demo/Triangulation_3/icons/fileSave.png b/Triangulation_3/demo/Triangulation_3/icons/fileSave.png new file mode 100644 index 0000000000000000000000000000000000000000..8feec99bee8685290ec292e7baeb2e23ba4bdf0c GIT binary patch literal 1205 zcmV;m1WNmfP)NMq!WhGU zDb0?ir%%5E<_$1MjY0D7B#lW{;<)?El`Cg|1R~9@%$x6h^uLpO_>ug@xmmgJ*No_P znnEHG0)+hmDMa6YiFRG4o_LlgUp&G194;$ z#|Q7e%Hu~Tky2s+BT^*7)&c<-q*B=0DRAb}Cf_b=^dCQH;0Q1UG+z@p-S0s>z(fLJdaXofa#Y{a{XE!DHR|93_w4?hG<8kq+lom3=aj}y`daH}yY*TMGX*PU}a?k^Z$mMe=dBBKr3MP(B@#**TcTpzBa|A=h93v%QS-kjptJB{4u^z@&y0LCI4T6TSa45CS|$;yRAqEsIM__GKF%A16&yfb3{?Ev3O= zWp`NK(`0awX_vDHsHDgM8ZYP2344@ECC0|a7#$t8fc=zn6g_`~Gzu^#jRElxKudw6 z9$4;tmaREZLZad}%d_8@%6e3-*Khp}bb(|KKnidjfs}wT93TtVTG{6kY+YmJ^6l=8 z>lZ#>U;q0&umyDY?jo%iDv^z46gTJE4_y{w-(;l(uB)>!J7T{u)|M^Y%M$(Q0;0yWQjJ)lC|WuBldAVWm>@ zYqi>@@7LCS|K4h~T3%gTynM%)v;o`!%0SCx>I0b8{Dmvcx$`r{^6IAfuzWTu7V=>n zht*cAvEloba;37qRxV#(t5)yUfG*GhflRd$wsDcfR`M{f{>xbi>|uW%=st z#`gB=U1QP^==3?TwFS`Yb4+F%ysJLI!or#FfIoo|Kmay)=NJKTf0)V094!6;(N7PE TmU#bB00000NkvXXu0mjf&~!wG literal 0 HcmV?d00001 diff --git a/Triangulation_3/demo/Triangulation_3/icons/flat.png b/Triangulation_3/demo/Triangulation_3/icons/flat.png new file mode 100644 index 0000000000000000000000000000000000000000..e48d6fc39a477a6c79f9504e74862aff593b9781 GIT binary patch literal 2326 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 Oh!wm%R8X;0oc$NfI;DmH literal 0 HcmV?d00001 diff --git a/Triangulation_3/demo/Triangulation_3/icons/grid.jpeg b/Triangulation_3/demo/Triangulation_3/icons/grid.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..3df03a6a79048c3ccb8d55475d6f2f02068c4eb6 GIT binary patch literal 798 zcmex=~;k+`^QRlZ%U&n^%&LPtsIH zM8y;gG$E8egfcZX0Wl0TO-#*9O`&q8I$B^^&Ho1&1UVQK7!;Tpl^B==8JPtc{~uwH zU|?VdITQg{SlO5vfHL|53`~s7Ow8;|>`-||CT12^K_Nv3VM7s7C1oSWK(>RbiG__5 zAAV2)Y7l1x8ig=~A?-XW(YlBwUu$l@wIJAT5^ zC0A-A@36k!cDwpRh{@JTw^TBoHzt`!nyhy4X1>iIye7T&SIO6K;RB%AZ%L4N-k>}9l;E?W2Qx7e(%gvI_kQe~<&?XMr-&-qik zBlpX_Ougw*QMx{Xx{LC$7 ztNpKYH~CfN{w+AFdu8uq^9QTKr_At+iO&1|_1N!vnZjRb+l-Zh;R?rl?=>yz_C5SoT^||BULluI}w@mWnOfjC0bxnBTvt;8qoK_0fEhnYs4LvmGv* zHqJ6JY`GLZQ;o0Wc>y1{U}KN5*6YxQn14%~mfbZu?dz;jnQf~ZsPrZzIj1zZM~;k+`^QRlZ%U&n^%&LPtsIH zPQ?@g44^cOGJ-Ko^-N85fE*)JO*1VWO%qMc{|6WZIT&Oa6qp&67?=bZnFSgDA7PMW zU|?bfx)A}`*cljEnSoO30t}4IK)}KblVoIKW?^6zWD`;hN}Q-<=oH8{+$w*epd@D6`pTZ%5dIcSlHERu+&`5dghJSdaMg0 zEG(3pPblqv4>ZAh{o!fWe^+}u$6l&ldsx?M+FO4oUftHZOXZ^T1JA3o)cod3yri~c7Tzhm1`vgCSz`G5c3hEPhMMBn!oK;IqxY2y2NhgHm;FQ_3=djAqp+Hr MUyiFmBjo>006+kZlmGw# literal 0 HcmV?d00001 diff --git a/Triangulation_3/demo/Triangulation_3/icons/insert_point.jpg b/Triangulation_3/demo/Triangulation_3/icons/insert_point.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7d9bdd7ae9a204808f4090fb4ac135ed74dbcc88 GIT binary patch literal 1685 zcmbu6dpOi-6vyA+TwF$0qsDb@TZ}~a5UrXAA!;a>>E^zO8Ivd(xy;rkUA1Q15)DP7 zm@ulXB)4p$%@|GCWX2^T`%_HAn3*%u80fYb

h~l>s4;D71>InmR^9A*fjh5D*fHKq1j+l;RLjlHwhpuxRb2>+Dq) z?Fv#|7QJ}=@$^D9V~5ImoM#7YvLQI;ggQn?S5MynZ@S!Ug}J4b^+p@pO^#cgoL#oL zx_No~kaq9cyYI)4(69sH5#+;1Vvokr;*b4&GUZh2=`&{;%#6&e?3_!vSFaTnUoW{) zT2@ufskw9a-mmu?8k?G*wEXt8mD|bdddYv)-6IeV3=R#y9T|N$`QhW#wCIy~W>(1s z0p$G2{*_B{1PFmbAyKMIE(j5)1jnM#OV_Dr+wW2hie9vA{c*L$4(WxJ_3FkOJYigL zOb15C#8QBtRHA(*`)^<;{ukLi*gsr7U;z?Rd>#@D2tYP#MJcZ2*8K36XDP+6oRajG zbj1c5x^?RG_3XX8lgH~Dt>;L-KQ%mMUE_xgUVqL@4RMgC-o-aA4JZ1OLOSqK?QU6(yMdyC`p32MAR?QJ#H62xlbYrf#b&8 z2cooSEq>pjxof5^k_<)eHIp7qTe(*69Y!OCFDx&r)7FmV63!iDPd%Ns7>V8NK)`8v zULmGsCTgzSVVvF3X0fx_(J03@=r$(*7-uvohL)}G)E|C7Ju}eJ}*AnKgIjE;5uY2g%L|4Ul6LtSIIi8<$!ybwct>W$2hwznvM}9*DwR4b6D^5 zWSLsGg2yBQ)U&O%R|1w$nWUkMJPL34rdJl*EX@SLg^MJ-VtB59(@3 znGEmp@wJ>JR#jtIa;MRn(97K6Y<_rSR-SF?hi1Pwvlwv=Jo`+@Z>T%N!c4Dn7<27> zWSU5rWHpXSNzKNLPdln6S*ccQzVRdLM7M7B^xJD+>U#JfBi*pwz~Yx8{@@|C1^#6``;F0w}C@mpN^UVDOQhl#}Q} zze(BE^HgHeJYaTf5s`ZmD<1IXkK4Jx1$}-qJt>Xh2C)^HH^~MCT`U~;N2Gz z2m*JlhC`wQ7uwc}9}?rkj+A(H^M}YO%lGGZ#$3oJR}^*5Hf4kq>U#~=y0*)~4u1_X z1s)UB&EZ*a#T?YnhUg7R1AYm@-D!0K4Y(pj5G5vVF{YJ_*TGD&95l0D9n~Sg>0*8p zJ*Z07H%Y1#wa4w27_mhu(w1&P_soQ`{<$X!TIIq@8+MssG!TBXhfS*Mf-~Z4({xg6 zGHSEF%eJh|#3XV`KW@)5pOAxCM~##QNmQBOM$n_`)1_yd5-^q{l0+X$LL@QjfS$zH U$$yW;t#i0^i%m{bQBhGDr6H?QZ_OU3<@cpH2ES>gE%7yAejXW1SV#Xgdn;E zBhU%|Z!z#NgBZ+$4E7AK|1JJk_Rl>q@7;vJ2Radt-W^QtF^h9kXVChtGH;fp0?*_I zlkWVRDR&?H-p%!ld@g*FlXDvDagHUgYHxgU`gVHqx=8EHjr+o{dA#w~itLlRRy!>+ za(csLi$}|+Usm4vcuvCeZF56+O?xODHshqEN{Zn-J`VfFt6JYqeop%sHrH9^oAxo` ztTiE9LX_TIQ(=Fvn)bBkC(94@u(z9fs%uRfW$$i^^GvbKl$o>H@RR3dcMYd|LDeF+ zdOhww-N9pXKrt!E;N0Q!2n$$fmoR>d!SZsvth4e6fUwQJv1SIhkFU43rVq~C)57a84s zPP_^&;QXyJZ~3y>Z#8$Q1o0kStUfR4(VrP=)`naQ<~-lRwoblrjd|8D{SF*w~? literal 0 HcmV?d00001 diff --git a/Triangulation_3/demo/Triangulation_3/icons/nearest_nb.png b/Triangulation_3/demo/Triangulation_3/icons/nearest_nb.png new file mode 100644 index 0000000000000000000000000000000000000000..53152fcf2f359ce998cf9713e9d76ea2e189fed7 GIT binary patch literal 3087 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 KugmKH-vj`?cofb6 literal 0 HcmV?d00001 diff --git a/Triangulation_3/demo/Triangulation_3/icons/pause.jpeg b/Triangulation_3/demo/Triangulation_3/icons/pause.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..2b7e2061bf65cba4aa4bce0ece2d01a8a10d7e52 GIT binary patch literal 1017 zcmex=bk%rt>aO-)Tx9UVMC{RR^f`?sp>aZie{xm`6PX9+|)AbmUn^wasTjwn3AvMj5FVEY~5VwyC_>EBY5Sp zNorHpr)^p5(eKI28FF#wm95Jc$e5aaEzr1>8YRoG`1G7()d34n-DTUQp30=o>4?fb zRLYWR^H{Cv$l5!8Hu2ZmjIzwKLhIyT-H~qaH2zy=^__)5WY3jL@1D(;{w&0>E@X99 za+UDMB_-VFPnH||_WtZ-5La1sYsbBYKbeBhXA3<#d*bTv4eQse%u=x8k7~SoQ*C>t z?pvEIhV6GMa(&nxUkBLk`m?=M2PnkxY-9ZL%imY{HdJeCx!PadW1(68ZvKtvBTaL1 zZbrnn|Ju%0u*lls8GB;sqdQt3ejSjQzTo}g&UMHB9O#!S=2-66-~9%n|oO<9|>=#_@x!gZ)-U3U0OYgN)!}ydGE{n{vh<|aQYlFZ?ZDUnk zwaT;FMhvN+W?3HC=_~VK=IQmB^*U!iy=8GP^|)x+@%sehbIrwbxTjn^$M5xO;<94F z@6#W6-Mzl0e^$Cc?E$X)g V?a0F!_uHF%v@$NHU1Ruv695O(exd*X literal 0 HcmV?d00001 diff --git a/Triangulation_3/demo/Triangulation_3/icons/play.jpeg b/Triangulation_3/demo/Triangulation_3/icons/play.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..e29a52e6c92a6f63ad96d66201663926abc0df8e GIT binary patch literal 799 zcmex=4n+V~MmA;^b|#>txc~zr z6AKFy8yh!Nnvsc_frV9&O-RvEDN$I&&?s;ryKzuq<3mwpCzqnhixzJ@_yMR6dFtCD*low8Ep3THoK`d4^_;ZuD4`|D5IZPwnI*n7vm;P3k>Daq0k9=ue!<5auEvdB(MaAT*f z{C>5iX9GU_7~Wc$D!o>|Z@8-EQ^R2X0(dw>zn&NazlS|qAj)ati>H~?=Ifa`(Ut#gEDw%ys;r0MYLN$xC;lTm)2E5oF(9-a5%nS+2!>B7PdAsIJ*OC-*G_KIz@ zlV@MI*Vj6ITvOX(aOU$?#>jO`mL@#QoXV$Erjo;Uh(n?8 RXy__EosA(H2krmg1OQDXA9nx% literal 0 HcmV?d00001 diff --git a/Triangulation_3/demo/Triangulation_3/icons/pointRandom.png b/Triangulation_3/demo/Triangulation_3/icons/pointRandom.png new file mode 100644 index 0000000000000000000000000000000000000000..a296047db38a33c8f17f585f257ea37ddadd9df2 GIT binary patch literal 1585 zcmb7EYfw{16h1fRk{F}}Oh82?v13IeC?gi5)x;EvsKsCvi713e5Fd~)TBkU6%F_p#2QE<#rU8=6;uQ?fK`!!UaHtDhNPE1{`6P7J3G7Qo3r1yXV00F zD~t$pqfMa!fLr*AkhK5^aYTUXLTsDl-zAS(>1)FTU}&1!M;I;%tHMISIX3mRr@thS z@v;@7bO6_hV+(bgIVfR-vkqZJ=YQ&S~r3Sfn&#&40Z zwn)+>@_2ujExOPVxm0#Fw22V`GVZ7T!1k^!1R5+92MjXRBx70T+5^kgLD zxEs&kn&Rv}>8b23UgAhY(-vX9zm#Zf$0KL#HND8#h$a=7nEbMAD<0REYC|7$iqs6P(!KARg+W zB)F+{B)Zb#ZU2!(x7RKk6&zyYqY(!N4;H2ydsdzv*bUbTC-W4pEIYMsJ76hT*QRoy z+j#~7)6zdYa+|G}VJ4qF9g!&iqD|%b6!)w`^*w8SIiT5MFTR-hYL1x(3+k94M#U~R zk-->)Kol%Z_OD>a{(0>S)y?(JzUFgtSg*hK zO}8X6;J%lzVZB+a+rFWZCLU0KmD_*V{2-|M6GX3mU2KlVj!g<6B`mBueXMfsG!9Tt z0UrSx2*Gl_TSr0lY6hLA-$>1A=0*;73Sqm;j!m))vsnyt59`Da6+5V=;_i0_$;J#& zjmAEv$nIa6e|29R;>Ws{FGBdTz^g7`VSwL1q-qi{Ku^@)U(n1hM?A|nC#QwUKW;M9 zqM+HUp~n73)S!oJE5&V%hC&$JRg(bK!90{^*{bge!)yrsla`1UI6N;js?B>g=yyXb>pg@2W%(K5u zVJwbMyxJi}4O8-tJGAx;UB2J~NgRo#i5d#3u#S-+5%S=RO4ambjJ+h`3XjUW_pDwZ znPrcHlSkF(h|2X4yAp8-;a^exR5Ow8i0kM$zy$kT+{8PTtthT6$aUZ!W2A3o^EpLBgXW2nsbWRViLNN+qQxTGWhV zr9L$9=A1|A4u8(n6C(7IZuA@swi_B}%vy8j$kS82Ap=yEb89@Y-S9!(Vbf0L{NqOL z#28Kg1Bt)x9qqi?Yt1 zg%fUt`Nhej71lU}JmJEh^quY7b_8Uz@txXy(sR@5%|n4*O)(`m2w~&W7kPz!T3he^ z-!ikjS^ZCj1G{$rK5*1;6$cI{i!mmDFt>Ba=W}u#qPB5>9EUMMGtW)~i?@DhDU!aiCZNl0E4 zK_l1*(#N~hN;axdc?6T#1TPV?8Vmc>gKpUXEc|aD4$-YB8QkD;Y`mKy8qdPvzYOzo Y)wsq5~;&+`^QRlZ%U&n^%&LPtsIH zPQ?@%m}r`SxjGO*2&JhBjKe5@ci+Wc+`GL7IVq ziJ1}PR2X1oV`gDzVq^eH8VWElGBY!>va+*6Wf_^6Sr}Lag@hFy0~6Vl3=duuQBEps zT)0ux$avxhpcW~hk6DpSV_;wbn!(D(1e8+|WMBdUAQxsABNGENi=d*R5Ub+{5u?Dy zjsI^k@Gvt1oyRQ5V9#*t4pT_Fz~xrujI z@vEnA>(h-!x;(#~J!0CfY+dH9d2hjn#rNc<#yzdReRuJ$Z8CkgJ%Sht5?xj-SC`qn zzbep8I_J7v@WiDoojS>Z{!N!^MC@;OtiHl^Q`IPcrDnjXWZBs2!*V4_KGPl^-&Uwvz zZsFA8iCUhM7l^3ux@F^4e0pvCrn1asdTehs7rtHXH{}oK*99Lxy*@2hVs^mF;AqsV zu;}TNEUaJrc_&z>e8!{jN2hn=o!rR4WBvveQtU-ryytn%Y6@`syrqEWi^Q^BT|Uzm zLEYtM%qnf`aNs^uTJN3sc2i!{EnH3?ZqGP%D_mqnp-AP=NqVV#-iLxFFgV#5UtYOR zrR{mloLQ0HRUhWPDqlU}RYv$Lz1@YmM_(mriMCyvdvxnp(aHOM*CyRxe*DqKn}7a% zli#c(8ZKHh``thH=+M>4?N65E8s2edJHA$QVc6^glUy=gH7Bt-%5S}R)^1AJmK`^) zKDws0B7=i_XYpp`$%=x>7N3`M;O(OAAxpJQkbIeOjybQIV0slzC07|9XqPIiThCF}~7POgB3D&ep80 zIVC41Ox$|BP)1sAtN#`;*#$)@ZilA1?@O1SBXd0dtn95nYWskAjp4@CN7sY~To7U} zdY+cPafzCSldM)u(E73mw%u;>M9qp rM(uxL9C!9Dp7{LyXZEz*;$$E1NwcDLj6|fIu1?MWB;xX@{{Kw?*~xtI literal 0 HcmV?d00001 diff --git a/Triangulation_3/demo/Triangulation_3/icons/quit.jpeg b/Triangulation_3/demo/Triangulation_3/icons/quit.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..56b44df507c6f18e5aee9a0edcffb79c463d3c4e GIT binary patch literal 578 zcmex=~;k+`^QRlZ%U&n^%&LPtsIH zPQ?@*n4t<7fw;y%tPKl70$C`= zGcqwS3$h6Pzs0}<)WRglEXZKbaQWktR|*@pp6Z&Hdwbd3#CAz`vpX+!JuQ2WKR%yV z^Gc}bR*-$TTav%x@jG(%R2>r)RjERdqqb*Rx%-!q(02$kuq$u>ENpmor?|p2*VkNup^FbN$azg!6f&osWm2YB!1ahV2~De?)&IW<0OMz`%>V!Z literal 0 HcmV?d00001 diff --git a/Triangulation_3/demo/Triangulation_3/icons/select_hand.jpeg b/Triangulation_3/demo/Triangulation_3/icons/select_hand.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..a5cd5db00c265735296702b9424824e4fc380297 GIT binary patch literal 3039 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 literal 0 HcmV?d00001 diff --git a/Triangulation_3/demo/Triangulation_3/icons/show_delaunay.jpeg b/Triangulation_3/demo/Triangulation_3/icons/show_delaunay.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..505e2c847a1a3cb987c02b6ae9cf5380516799f5 GIT binary patch literal 5781 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 literal 0 HcmV?d00001 diff --git a/Triangulation_3/demo/Triangulation_3/icons/show_facet.jpeg b/Triangulation_3/demo/Triangulation_3/icons/show_facet.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..bb8c2701bf900ea7bc1276af7be770758036442b GIT binary patch literal 1201 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 PPS0z*&DBQ8{+oXT0y?a& literal 0 HcmV?d00001 diff --git a/Triangulation_3/demo/Triangulation_3/icons/stereo.png b/Triangulation_3/demo/Triangulation_3/icons/stereo.png new file mode 100644 index 0000000000000000000000000000000000000000..74788d1002868c7847f71435d346ff603e26a576 GIT binary patch literal 2350 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 aIqAu&-)tn{ry8#6azD~yh8Dwz|2F{vY(`fA literal 0 HcmV?d00001 diff --git a/Triangulation_3/demo/Triangulation_3/typedefs.h b/Triangulation_3/demo/Triangulation_3/typedefs.h new file mode 100644 index 00000000000..f754ff5a400 --- /dev/null +++ b/Triangulation_3/demo/Triangulation_3/typedefs.h @@ -0,0 +1,101 @@ +#ifndef TYPEDEFS_H +#define TYPEDEFS_H + +#include //dynamic array +#include //linked list + +// CGAL +#include +#include + +// Added for T3 demo +#include +#include + +// Use EPEC as Kernel +// Note: the computation of VD requires exact constructions; +// while computing the triangulation only requires exact predicates. +typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; + +// Ddefine field type +typedef Kernel::FT FT; + +typedef Kernel::Vector_3 Vector_3; +typedef Kernel::Direction_3 Direction_3; + +//typedef Kernel::Point_3 Point_3; +//typedef Kernel::Vector_3 Vector_3; +//typedef Kernel::Segment_3 Segment_3; +//typedef Kernel::Triangle_3 Triangle_3; + +// Added for T3 demo + +/* + * The user has several ways to add his own data in the vertex + * and cell base classes used by the TDS. He can either: * 1. use the classes Triangulation vertex base with info + * and Triangulation cell base with info, which allow to + * add one data member of a user provided type, and give access to it. * 2. derive his own classes from the default base classes + * Triangulation ds vertex base, and Triangulation ds cell base + * (or the geometric versions typically used by the geometric layer, + * Triangulation vertex base, and Triangulation cell base). * 3. write his own base classes following the requirements given by the concepts + * TriangulationCellBase 3 and TriangulationVertexBase 3 + * (described in page 2494 and page 2495). + */ +/* add index and color to vertex class */ +template < class GT, class Vb=CGAL::Triangulation_vertex_base_3 > +class Vertex_base : public Vb +{ +public: + typedef typename Vb::Point Point; + typedef typename Vb::Vertex_handle Vertex_handle; + typedef typename Vb::Cell_handle Cell_handle; + + template < class TDS2 > + struct Rebind_TDS { + typedef typename Vb::template Rebind_TDS::Other Vb2; + typedef Vertex_base< GT, Vb2 > Other; + }; + Vertex_base() + : m_isSelected(false) {} + Vertex_base(const Point& p) + : Vb(p), m_isSelected(false) {} + Vertex_base(const Point& p, Cell_handle c) + : Vb(p, c), m_isSelected(false) {} + + inline bool isSeled() const { return m_isSelected; } + inline void setSeled(bool flag=true) { m_isSelected = flag; } + +private: + bool m_isSelected; // whether it is selected +}; + +typedef CGAL::Triangulation_data_structure_3< Vertex_base > Tds; +/* + * Delaunay_triangulation_3 + * arg1: a model of the DelaunayTriangulationTraits_3 concept + * arg2: a model of the TriangulationDataStructure_3 concept + * default: Triangulation_data_structure_3 + * arg3: Fast_location or Compact_location (default) + * Fast_location offers O(logn) time point location, using additional data structure, + * good for fast point locations or random point insertions + * Compact_location saves memory by avoiding the separate data structure + * and point location is then O(n^(1/3)) time + */ +typedef CGAL::Delaunay_triangulation_3 DT3; + +typedef DT3::Object Object_3; +typedef DT3::Point Point_3; +typedef DT3::Segment Segment_3; +typedef DT3::Ray Ray_3; +typedef DT3::Triangle Triangle_3; + +typedef DT3::Vertex_handle Vertex_handle; +typedef DT3::Finite_vertices_iterator vertices_iterator; +typedef DT3::Edge Edge; +typedef DT3::Finite_edges_iterator edges_iterator; +typedef DT3::Facet Facet; +typedef DT3::Finite_facets_iterator facets_iterator; +typedef DT3::Cell_handle Cell_handle; +typedef DT3::Finite_cells_iterator cells_iterator; + +#endif diff --git a/Triangulation_3/demo/Triangulation_3/ui_MainWindow.h b/Triangulation_3/demo/Triangulation_3/ui_MainWindow.h new file mode 100644 index 00000000000..2e7cf4df3b2 --- /dev/null +++ b/Triangulation_3/demo/Triangulation_3/ui_MainWindow.h @@ -0,0 +1,584 @@ +/******************************************************************************** +** Form generated from reading ui file 'MainWindow.ui' +** +** Created: Mon Dec 20 14:14:32 2010 +** by: Qt User Interface Compiler version 4.4.1 +** +** WARNING! All changes made in this file will be lost when recompiling ui file! +********************************************************************************/ + +#ifndef UI_MAINWINDOW_H +#define UI_MAINWINDOW_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Viewer.h" + +QT_BEGIN_NAMESPACE + +class Ui_MainWindow +{ +public: + QAction *actionGenerate_Points; + QAction *actionLoad_Points; + QAction *actionSave_Points; + QAction *actionShow_Axis; + QAction *actionQuit; + QAction *actionClear_Scene; + QAction *actionShow_Vertex; + QAction *actionShow_DEdge; + QAction *actionShow_VEdge; + QAction *actionShow_Facet; + QAction *actionFlat; + QAction *actionPreferences; + QAction *actionInsert_Vertex; + QAction *actionInsert_Point; + QAction *actionSelect_Vertex; + QAction *actionMove_Vertex; + QAction *actionFind_NearestNb; + QAction *actionEmpty_Sphere; + QAction *actionNormal_View; + QAction *actionDemo_Help; + QAction *actionIncremental_Construct; + QAction *actionStop_Animation; + QAction *actionAbout_T3_demo; + QWidget *centralwidget; + QHBoxLayout *horizontalLayout; + Viewer *viewer; + QMenuBar *menubar; + QMenu *menuFile; + QMenu *menuEdit; + QMenu *menuMode; + QMenu *menuShow; + QMenu *menuHelp; + QStatusBar *statusbar; + QToolBar *toolBar; + + void setupUi(QMainWindow *MainWindow) + { + if (MainWindow->objectName().isEmpty()) + MainWindow->setObjectName(QString::fromUtf8("MainWindow")); + MainWindow->setWindowModality(Qt::NonModal); + MainWindow->resize(1100, 500); + QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + sizePolicy.setHorizontalStretch(0); + sizePolicy.setVerticalStretch(0); + sizePolicy.setHeightForWidth(MainWindow->sizePolicy().hasHeightForWidth()); + MainWindow->setSizePolicy(sizePolicy); + QFont font; + font.setFamily(QString::fromUtf8("Arial")); + MainWindow->setFont(font); + MainWindow->setCursor(QCursor(Qt::PointingHandCursor)); + QIcon icon; + icon.addPixmap(QPixmap(QString::fromUtf8(":/T3_demo/icons/icons/cgal_logo.xpm")), QIcon::Normal, QIcon::Off); + MainWindow->setWindowIcon(icon); + actionGenerate_Points = new QAction(MainWindow); + actionGenerate_Points->setObjectName(QString::fromUtf8("actionGenerate_Points")); + QIcon icon1; + icon1.addPixmap(QPixmap(QString::fromUtf8(":/T3_demo/icons/icons/pointRandom.png")), QIcon::Normal, QIcon::Off); + actionGenerate_Points->setIcon(icon1); + actionLoad_Points = new QAction(MainWindow); + actionLoad_Points->setObjectName(QString::fromUtf8("actionLoad_Points")); + QIcon icon2; + icon2.addPixmap(QPixmap(QString::fromUtf8(":/T3_demo/icons/icons/fileOpen.png")), QIcon::Normal, QIcon::Off); + actionLoad_Points->setIcon(icon2); + actionSave_Points = new QAction(MainWindow); + actionSave_Points->setObjectName(QString::fromUtf8("actionSave_Points")); + QIcon icon3; + icon3.addPixmap(QPixmap(QString::fromUtf8(":/T3_demo/icons/icons/fileSave.png")), QIcon::Normal, QIcon::Off); + actionSave_Points->setIcon(icon3); + actionShow_Axis = new QAction(MainWindow); + actionShow_Axis->setObjectName(QString::fromUtf8("actionShow_Axis")); + actionShow_Axis->setCheckable(true); + QIcon icon4; + icon4.addPixmap(QPixmap(QString::fromUtf8(":/T3_demo/icons/icons/coordinates.jpeg")), QIcon::Normal, QIcon::Off); + actionShow_Axis->setIcon(icon4); + actionQuit = new QAction(MainWindow); + actionQuit->setObjectName(QString::fromUtf8("actionQuit")); + QIcon icon5; + icon5.addPixmap(QPixmap(QString::fromUtf8(":/T3_demo/icons/icons/quit.jpeg")), QIcon::Normal, QIcon::Off); + actionQuit->setIcon(icon5); + actionClear_Scene = new QAction(MainWindow); + actionClear_Scene->setObjectName(QString::fromUtf8("actionClear_Scene")); + QIcon icon6; + icon6.addPixmap(QPixmap(QString::fromUtf8(":/T3_demo/icons/icons/clear.jpeg")), QIcon::Normal, QIcon::Off); + actionClear_Scene->setIcon(icon6); + actionShow_Vertex = new QAction(MainWindow); + actionShow_Vertex->setObjectName(QString::fromUtf8("actionShow_Vertex")); + actionShow_Vertex->setCheckable(true); + actionShow_Vertex->setChecked(true); + QIcon icon7; + icon7.addPixmap(QPixmap(QString::fromUtf8(":/T3_demo/icons/icons/show_point.jpeg")), QIcon::Normal, QIcon::Off); + actionShow_Vertex->setIcon(icon7); + actionShow_DEdge = new QAction(MainWindow); + actionShow_DEdge->setObjectName(QString::fromUtf8("actionShow_DEdge")); + actionShow_DEdge->setCheckable(true); + actionShow_DEdge->setChecked(true); + QIcon icon8; + icon8.addPixmap(QPixmap(QString::fromUtf8(":/T3_demo/icons/icons/show_delaunay.jpeg")), QIcon::Normal, QIcon::Off); + actionShow_DEdge->setIcon(icon8); + actionShow_VEdge = new QAction(MainWindow); + actionShow_VEdge->setObjectName(QString::fromUtf8("actionShow_VEdge")); + actionShow_VEdge->setCheckable(true); + QIcon icon9; + icon9.addPixmap(QPixmap(QString::fromUtf8(":/T3_demo/icons/icons/show_voronoi.jpeg")), QIcon::Normal, QIcon::Off); + actionShow_VEdge->setIcon(icon9); + actionShow_Facet = new QAction(MainWindow); + actionShow_Facet->setObjectName(QString::fromUtf8("actionShow_Facet")); + actionShow_Facet->setCheckable(true); + QIcon icon10; + icon10.addPixmap(QPixmap(QString::fromUtf8(":/T3_demo/icons/icons/show_facet.jpeg")), QIcon::Normal, QIcon::Off); + actionShow_Facet->setIcon(icon10); + actionFlat = new QAction(MainWindow); + actionFlat->setObjectName(QString::fromUtf8("actionFlat")); + actionFlat->setCheckable(true); + QIcon icon11; + icon11.addPixmap(QPixmap(QString::fromUtf8(":/T3_demo/icons/icons/flat.png")), QIcon::Normal, QIcon::Off); + icon11.addPixmap(QPixmap(QString::fromUtf8(":/T3_demo/icons/icons/stereo.png")), QIcon::Normal, QIcon::On); + actionFlat->setIcon(icon11); + actionPreferences = new QAction(MainWindow); + actionPreferences->setObjectName(QString::fromUtf8("actionPreferences")); + QIcon icon12; + icon12.addPixmap(QPixmap(QString::fromUtf8(":/T3_demo/icons/icons/preferences.jpeg")), QIcon::Normal, QIcon::Off); + actionPreferences->setIcon(icon12); + actionInsert_Vertex = new QAction(MainWindow); + actionInsert_Vertex->setObjectName(QString::fromUtf8("actionInsert_Vertex")); + actionInsert_Vertex->setCheckable(true); + QIcon icon13; + icon13.addPixmap(QPixmap(QString::fromUtf8(":/T3_demo/icons/icons/insert.jpeg")), QIcon::Normal, QIcon::Off); + actionInsert_Vertex->setIcon(icon13); + actionInsert_Point = new QAction(MainWindow); + actionInsert_Point->setObjectName(QString::fromUtf8("actionInsert_Point")); + actionInsert_Point->setCheckable(true); + QIcon icon14; + icon14.addPixmap(QPixmap(QString::fromUtf8(":/T3_demo/icons/icons/insert_point.jpg")), QIcon::Normal, QIcon::Off); + actionInsert_Point->setIcon(icon14); + actionSelect_Vertex = new QAction(MainWindow); + actionSelect_Vertex->setObjectName(QString::fromUtf8("actionSelect_Vertex")); + actionSelect_Vertex->setCheckable(true); + QIcon icon15; + icon15.addPixmap(QPixmap(QString::fromUtf8(":/T3_demo/icons/icons/select_hand.jpeg")), QIcon::Normal, QIcon::Off); + actionSelect_Vertex->setIcon(icon15); + actionMove_Vertex = new QAction(MainWindow); + actionMove_Vertex->setObjectName(QString::fromUtf8("actionMove_Vertex")); + actionMove_Vertex->setCheckable(true); + QIcon icon16; + icon16.addPixmap(QPixmap(QString::fromUtf8(":/T3_demo/icons/icons/move_1.jpeg")), QIcon::Normal, QIcon::Off); + actionMove_Vertex->setIcon(icon16); + actionFind_NearestNb = new QAction(MainWindow); + actionFind_NearestNb->setObjectName(QString::fromUtf8("actionFind_NearestNb")); + actionFind_NearestNb->setCheckable(true); + QIcon icon17; + icon17.addPixmap(QPixmap(QString::fromUtf8(":/T3_demo/icons/icons/nearest_nb.png")), QIcon::Normal, QIcon::Off); + actionFind_NearestNb->setIcon(icon17); + actionEmpty_Sphere = new QAction(MainWindow); + actionEmpty_Sphere->setObjectName(QString::fromUtf8("actionEmpty_Sphere")); + actionEmpty_Sphere->setCheckable(true); + QIcon icon18; + icon18.addPixmap(QPixmap(QString::fromUtf8(":/T3_demo/icons/icons/empty_sphere.jpeg")), QIcon::Normal, QIcon::Off); + actionEmpty_Sphere->setIcon(icon18); + actionNormal_View = new QAction(MainWindow); + actionNormal_View->setObjectName(QString::fromUtf8("actionNormal_View")); + actionNormal_View->setCheckable(true); + actionNormal_View->setChecked(true); + QIcon icon19; + icon19.addPixmap(QPixmap(QString::fromUtf8(":/T3_demo/icons/icons/normal_view.jpeg")), QIcon::Normal, QIcon::Off); + actionNormal_View->setIcon(icon19); + actionDemo_Help = new QAction(MainWindow); + actionDemo_Help->setObjectName(QString::fromUtf8("actionDemo_Help")); + actionIncremental_Construct = new QAction(MainWindow); + actionIncremental_Construct->setObjectName(QString::fromUtf8("actionIncremental_Construct")); + actionIncremental_Construct->setCheckable(true); + QIcon icon20; + icon20.addPixmap(QPixmap(QString::fromUtf8(":/T3_demo/icons/icons/play.jpeg")), QIcon::Normal, QIcon::Off); + icon20.addPixmap(QPixmap(QString::fromUtf8(":/T3_demo/icons/icons/pause.jpeg")), QIcon::Normal, QIcon::On); + actionIncremental_Construct->setIcon(icon20); + actionStop_Animation = new QAction(MainWindow); + actionStop_Animation->setObjectName(QString::fromUtf8("actionStop_Animation")); + QIcon icon21; + icon21.addPixmap(QPixmap(QString::fromUtf8(":/T3_demo/icons/icons/stop.jpeg")), QIcon::Normal, QIcon::Off); + actionStop_Animation->setIcon(icon21); + actionAbout_T3_demo = new QAction(MainWindow); + actionAbout_T3_demo->setObjectName(QString::fromUtf8("actionAbout_T3_demo")); + centralwidget = new QWidget(MainWindow); + centralwidget->setObjectName(QString::fromUtf8("centralwidget")); + horizontalLayout = new QHBoxLayout(centralwidget); + horizontalLayout->setSpacing(3); + horizontalLayout->setMargin(1); + horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout")); + viewer = new Viewer(centralwidget); + viewer->setObjectName(QString::fromUtf8("viewer")); + sizePolicy.setHeightForWidth(viewer->sizePolicy().hasHeightForWidth()); + viewer->setSizePolicy(sizePolicy); + viewer->setCursor(QCursor(Qt::PointingHandCursor)); + + horizontalLayout->addWidget(viewer); + + MainWindow->setCentralWidget(centralwidget); + menubar = new QMenuBar(MainWindow); + menubar->setObjectName(QString::fromUtf8("menubar")); + menubar->setGeometry(QRect(0, 0, 1010, 22)); + menuFile = new QMenu(menubar); + menuFile->setObjectName(QString::fromUtf8("menuFile")); + menuEdit = new QMenu(menubar); + menuEdit->setObjectName(QString::fromUtf8("menuEdit")); + menuMode = new QMenu(menubar); + menuMode->setObjectName(QString::fromUtf8("menuMode")); + menuShow = new QMenu(menubar); + menuShow->setObjectName(QString::fromUtf8("menuShow")); + menuHelp = new QMenu(menubar); + menuHelp->setObjectName(QString::fromUtf8("menuHelp")); + MainWindow->setMenuBar(menubar); + statusbar = new QStatusBar(MainWindow); + statusbar->setObjectName(QString::fromUtf8("statusbar")); + MainWindow->setStatusBar(statusbar); + toolBar = new QToolBar(MainWindow); + toolBar->setObjectName(QString::fromUtf8("toolBar")); + MainWindow->addToolBar(Qt::TopToolBarArea, toolBar); + + menubar->addAction(menuFile->menuAction()); + menubar->addAction(menuEdit->menuAction()); + menubar->addAction(menuMode->menuAction()); + menubar->addAction(menuShow->menuAction()); + menubar->addAction(menuHelp->menuAction()); + menuFile->addAction(actionLoad_Points); + menuFile->addAction(actionSave_Points); + menuFile->addSeparator(); + menuFile->addAction(actionQuit); + menuEdit->addAction(actionGenerate_Points); + menuEdit->addSeparator(); + menuEdit->addAction(actionIncremental_Construct); + menuEdit->addAction(actionStop_Animation); + menuEdit->addSeparator(); + menuEdit->addAction(actionClear_Scene); + menuMode->addAction(actionNormal_View); + menuMode->addAction(actionInsert_Vertex); + menuMode->addAction(actionInsert_Point); + menuMode->addAction(actionSelect_Vertex); + menuMode->addAction(actionMove_Vertex); + menuMode->addAction(actionFind_NearestNb); + menuMode->addAction(actionEmpty_Sphere); + menuShow->addAction(actionShow_Axis); + menuShow->addSeparator(); + menuShow->addAction(actionShow_Vertex); + menuShow->addAction(actionShow_DEdge); + menuShow->addAction(actionShow_VEdge); + menuShow->addAction(actionShow_Facet); + menuShow->addSeparator(); + menuShow->addAction(actionFlat); + menuShow->addSeparator(); + menuShow->addAction(actionPreferences); + menuHelp->addAction(actionDemo_Help); + menuHelp->addAction(actionAbout_T3_demo); + toolBar->addAction(actionLoad_Points); + toolBar->addAction(actionSave_Points); + toolBar->addSeparator(); + toolBar->addAction(actionGenerate_Points); + toolBar->addAction(actionClear_Scene); + toolBar->addSeparator(); + toolBar->addAction(actionIncremental_Construct); + toolBar->addAction(actionStop_Animation); + toolBar->addSeparator(); + toolBar->addAction(actionShow_Axis); + toolBar->addSeparator(); + toolBar->addAction(actionFlat); + toolBar->addSeparator(); + toolBar->addAction(actionShow_Vertex); + toolBar->addAction(actionShow_DEdge); + toolBar->addAction(actionShow_VEdge); + toolBar->addAction(actionShow_Facet); + toolBar->addSeparator(); + toolBar->addAction(actionNormal_View); + toolBar->addAction(actionInsert_Vertex); + toolBar->addAction(actionInsert_Point); + toolBar->addAction(actionSelect_Vertex); + toolBar->addAction(actionMove_Vertex); + toolBar->addAction(actionFind_NearestNb); + toolBar->addAction(actionEmpty_Sphere); + toolBar->addSeparator(); + toolBar->addAction(actionPreferences); + toolBar->addSeparator(); + toolBar->addAction(actionQuit); + + retranslateUi(MainWindow); + + QMetaObject::connectSlotsByName(MainWindow); + } // setupUi + + void retranslateUi(QMainWindow *MainWindow) + { + MainWindow->setWindowTitle(QApplication::translate("MainWindow", "Triangulation_demo_3", 0, QApplication::UnicodeUTF8)); + actionGenerate_Points->setText(QApplication::translate("MainWindow", "Generate Points", 0, QApplication::UnicodeUTF8)); + +#ifndef QT_NO_TOOLTIP + actionGenerate_Points->setToolTip(QApplication::translate("MainWindow", "Generate Points", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_TOOLTIP + + +#ifndef QT_NO_STATUSTIP + actionGenerate_Points->setStatusTip(QApplication::translate("MainWindow", "Generate Points", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_STATUSTIP + + actionGenerate_Points->setShortcut(QApplication::translate("MainWindow", "Ctrl+G", 0, QApplication::UnicodeUTF8)); + actionLoad_Points->setText(QApplication::translate("MainWindow", "Load Points...", 0, QApplication::UnicodeUTF8)); + +#ifndef QT_NO_TOOLTIP + actionLoad_Points->setToolTip(QApplication::translate("MainWindow", "Load Points from a file", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_TOOLTIP + + +#ifndef QT_NO_STATUSTIP + actionLoad_Points->setStatusTip(QApplication::translate("MainWindow", "Load Points from a file", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_STATUSTIP + + actionLoad_Points->setShortcut(QApplication::translate("MainWindow", "Ctrl+O", 0, QApplication::UnicodeUTF8)); + actionSave_Points->setText(QApplication::translate("MainWindow", "Save Points...", 0, QApplication::UnicodeUTF8)); + +#ifndef QT_NO_TOOLTIP + actionSave_Points->setToolTip(QApplication::translate("MainWindow", "Save points to a file", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_TOOLTIP + + +#ifndef QT_NO_STATUSTIP + actionSave_Points->setStatusTip(QApplication::translate("MainWindow", "Save points to a file", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_STATUSTIP + + actionSave_Points->setShortcut(QApplication::translate("MainWindow", "Ctrl+S", 0, QApplication::UnicodeUTF8)); + actionShow_Axis->setText(QApplication::translate("MainWindow", "Show Axis", 0, QApplication::UnicodeUTF8)); + +#ifndef QT_NO_TOOLTIP + actionShow_Axis->setToolTip(QApplication::translate("MainWindow", "Show/Hide Axis", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_TOOLTIP + + +#ifndef QT_NO_STATUSTIP + actionShow_Axis->setStatusTip(QApplication::translate("MainWindow", "Show/Hide Axis", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_STATUSTIP + + actionQuit->setText(QApplication::translate("MainWindow", "Quit", 0, QApplication::UnicodeUTF8)); + +#ifndef QT_NO_TOOLTIP + actionQuit->setToolTip(QApplication::translate("MainWindow", "Quit", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_TOOLTIP + + +#ifndef QT_NO_STATUSTIP + actionQuit->setStatusTip(QApplication::translate("MainWindow", "Quit", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_STATUSTIP + + actionClear_Scene->setText(QApplication::translate("MainWindow", "Clear Scene", 0, QApplication::UnicodeUTF8)); + +#ifndef QT_NO_TOOLTIP + actionClear_Scene->setToolTip(QApplication::translate("MainWindow", "Clear Scene", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_TOOLTIP + + +#ifndef QT_NO_STATUSTIP + actionClear_Scene->setStatusTip(QApplication::translate("MainWindow", "Clear Scene", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_STATUSTIP + + actionShow_Vertex->setText(QApplication::translate("MainWindow", "Show Vertices", 0, QApplication::UnicodeUTF8)); + +#ifndef QT_NO_TOOLTIP + actionShow_Vertex->setToolTip(QApplication::translate("MainWindow", "Show Vertices", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_TOOLTIP + + +#ifndef QT_NO_STATUSTIP + actionShow_Vertex->setStatusTip(QApplication::translate("MainWindow", "Show Vertices", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_STATUSTIP + + actionShow_DEdge->setText(QApplication::translate("MainWindow", "Show Delaunay Edges", 0, QApplication::UnicodeUTF8)); + +#ifndef QT_NO_TOOLTIP + actionShow_DEdge->setToolTip(QApplication::translate("MainWindow", "Show Delaunay edges", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_TOOLTIP + + +#ifndef QT_NO_STATUSTIP + actionShow_DEdge->setStatusTip(QApplication::translate("MainWindow", "Show Delaunay edges", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_STATUSTIP + + actionShow_VEdge->setText(QApplication::translate("MainWindow", "Show Voronoi Edges", 0, QApplication::UnicodeUTF8)); + +#ifndef QT_NO_TOOLTIP + actionShow_VEdge->setToolTip(QApplication::translate("MainWindow", "Show Voronoi edges", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_TOOLTIP + + +#ifndef QT_NO_STATUSTIP + actionShow_VEdge->setStatusTip(QApplication::translate("MainWindow", "Show Voronoi edges", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_STATUSTIP + + actionShow_Facet->setText(QApplication::translate("MainWindow", "Show Facets", 0, QApplication::UnicodeUTF8)); + +#ifndef QT_NO_TOOLTIP + actionShow_Facet->setToolTip(QApplication::translate("MainWindow", "Show Delaunay Facets", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_TOOLTIP + + +#ifndef QT_NO_STATUSTIP + actionShow_Facet->setStatusTip(QApplication::translate("MainWindow", "Show Delaunay Facets", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_STATUSTIP + + actionFlat->setText(QApplication::translate("MainWindow", "Flat", 0, QApplication::UnicodeUTF8)); + +#ifndef QT_NO_TOOLTIP + actionFlat->setToolTip(QApplication::translate("MainWindow", "Toggle 3D effect", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_TOOLTIP + + +#ifndef QT_NO_STATUSTIP + actionFlat->setStatusTip(QApplication::translate("MainWindow", "Toggle 3D effect", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_STATUSTIP + + actionPreferences->setText(QApplication::translate("MainWindow", "Preferences...", 0, QApplication::UnicodeUTF8)); + +#ifndef QT_NO_TOOLTIP + actionPreferences->setToolTip(QApplication::translate("MainWindow", "Change Colors, Transparency, etc.", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_TOOLTIP + + +#ifndef QT_NO_STATUSTIP + actionPreferences->setStatusTip(QApplication::translate("MainWindow", "Change Colors, Transparency, etc.", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_STATUSTIP + + actionInsert_Vertex->setText(QApplication::translate("MainWindow", "Insert Vertex", 0, QApplication::UnicodeUTF8)); + +#ifndef QT_NO_TOOLTIP + actionInsert_Vertex->setToolTip(QApplication::translate("MainWindow", "Insert a vertex and update the triangulation", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_TOOLTIP + + +#ifndef QT_NO_STATUSTIP + actionInsert_Vertex->setStatusTip(QApplication::translate("MainWindow", "Insert a vertex and update the triangulation", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_STATUSTIP + + actionInsert_Point->setText(QApplication::translate("MainWindow", "Insert Point", 0, QApplication::UnicodeUTF8)); + +#ifndef QT_NO_TOOLTIP + actionInsert_Point->setToolTip(QApplication::translate("MainWindow", "Insert a point and show its conflict region", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_TOOLTIP + + +#ifndef QT_NO_STATUSTIP + actionInsert_Point->setStatusTip(QApplication::translate("MainWindow", "Insert a point and show its conflict region", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_STATUSTIP + + actionSelect_Vertex->setText(QApplication::translate("MainWindow", "Select Vertex", 0, QApplication::UnicodeUTF8)); + +#ifndef QT_NO_TOOLTIP + actionSelect_Vertex->setToolTip(QApplication::translate("MainWindow", "Select vertices", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_TOOLTIP + + +#ifndef QT_NO_STATUSTIP + actionSelect_Vertex->setStatusTip(QApplication::translate("MainWindow", "Select vertices", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_STATUSTIP + + actionMove_Vertex->setText(QApplication::translate("MainWindow", "Move Vertex", 0, QApplication::UnicodeUTF8)); + +#ifndef QT_NO_TOOLTIP + actionMove_Vertex->setToolTip(QApplication::translate("MainWindow", "Move a vertex", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_TOOLTIP + + +#ifndef QT_NO_STATUSTIP + actionMove_Vertex->setStatusTip(QApplication::translate("MainWindow", "Move a vertex", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_STATUSTIP + + actionFind_NearestNb->setText(QApplication::translate("MainWindow", "Nearest Neighbor Search", 0, QApplication::UnicodeUTF8)); + +#ifndef QT_NO_TOOLTIP + actionFind_NearestNb->setToolTip(QApplication::translate("MainWindow", "Find the nearest neighbor of the query point", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_TOOLTIP + + +#ifndef QT_NO_STATUSTIP + actionFind_NearestNb->setStatusTip(QApplication::translate("MainWindow", "Find the nearest neighbor of the query point", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_STATUSTIP + + actionEmpty_Sphere->setText(QApplication::translate("MainWindow", "Show Empty Sphere", 0, QApplication::UnicodeUTF8)); + actionEmpty_Sphere->setIconText(QApplication::translate("MainWindow", "Click to select a cell and show empty sphere of that cell.", 0, QApplication::UnicodeUTF8)); + +#ifndef QT_NO_TOOLTIP + actionEmpty_Sphere->setToolTip(QApplication::translate("MainWindow", "Locate the query point in a cell and show empty sphere of that cell", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_TOOLTIP + + +#ifndef QT_NO_STATUSTIP + actionEmpty_Sphere->setStatusTip(QApplication::translate("MainWindow", "Locate the query point in a cell and show empty sphere of that cell", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_STATUSTIP + + actionNormal_View->setText(QApplication::translate("MainWindow", "Normal Mode", 0, QApplication::UnicodeUTF8)); + +#ifndef QT_NO_TOOLTIP + actionNormal_View->setToolTip(QApplication::translate("MainWindow", "Normal Mode", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_TOOLTIP + + +#ifndef QT_NO_STATUSTIP + actionNormal_View->setStatusTip(QApplication::translate("MainWindow", "Normal Mode", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_STATUSTIP + + actionDemo_Help->setText(QApplication::translate("MainWindow", "Triangulation_3D Demo Help", 0, QApplication::UnicodeUTF8)); + +#ifndef QT_NO_TOOLTIP + actionDemo_Help->setToolTip(QApplication::translate("MainWindow", "Triangulation_3D Demo Help", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_TOOLTIP + + +#ifndef QT_NO_STATUSTIP + actionDemo_Help->setStatusTip(QApplication::translate("MainWindow", "Triangulation_3D Demo Help", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_STATUSTIP + + actionDemo_Help->setShortcut(QApplication::translate("MainWindow", "H", 0, QApplication::UnicodeUTF8)); + actionIncremental_Construct->setText(QApplication::translate("MainWindow", "Insertion Animation", 0, QApplication::UnicodeUTF8)); + +#ifndef QT_NO_TOOLTIP + actionIncremental_Construct->setToolTip(QApplication::translate("MainWindow", "Animation of incremental Delaunay triangulation", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_TOOLTIP + + +#ifndef QT_NO_STATUSTIP + actionIncremental_Construct->setStatusTip(QApplication::translate("MainWindow", "Animation of incremental Delaunay triangulation", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_STATUSTIP + + actionStop_Animation->setText(QApplication::translate("MainWindow", "Stop Animation", 0, QApplication::UnicodeUTF8)); + +#ifndef QT_NO_TOOLTIP + actionStop_Animation->setToolTip(QApplication::translate("MainWindow", "Stop Animation", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_TOOLTIP + + +#ifndef QT_NO_STATUSTIP + actionStop_Animation->setStatusTip(QApplication::translate("MainWindow", "Stop Animation", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_STATUSTIP + + actionAbout_T3_demo->setText(QApplication::translate("MainWindow", "About T3_demo", 0, QApplication::UnicodeUTF8)); + menuFile->setTitle(QApplication::translate("MainWindow", "&File", 0, QApplication::UnicodeUTF8)); + menuEdit->setTitle(QApplication::translate("MainWindow", "Edit", 0, QApplication::UnicodeUTF8)); + menuMode->setTitle(QApplication::translate("MainWindow", "Mode", 0, QApplication::UnicodeUTF8)); + menuShow->setTitle(QApplication::translate("MainWindow", "Show", 0, QApplication::UnicodeUTF8)); + menuHelp->setTitle(QApplication::translate("MainWindow", "Help", 0, QApplication::UnicodeUTF8)); + toolBar->setWindowTitle(QApplication::translate("MainWindow", "toolBar", 0, QApplication::UnicodeUTF8)); + } // retranslateUi + +}; + +namespace Ui { + class MainWindow: public Ui_MainWindow {}; +} // namespace Ui + +QT_END_NAMESPACE + +#endif // UI_MAINWINDOW_H