cgal/Mesh_3/demo/Mesh_3/Mesh_3_optimization_plugin.cpp

592 lines
17 KiB
C++

#include <boost/config.hpp>
#if defined(BOOST_MSVC)
# pragma warning( disable : 4503)
#endif
#include "config.h"
#ifdef CGAL_POLYHEDRON_DEMO_USE_SURFACE_MESHER
#include <CGAL_demo/Plugin_helper.h>
#include <CGAL_demo/Plugin_interface.h>
#include <CGAL_demo/Messages_interface.h>
#include "ui_Smoother_dialog.h"
#include "ui_LocalOptim_dialog.h"
#include "Scene_c3t3_item.h"
#include "C3t3_type.h"
#include "Optimizer_thread.h"
#include <QObject>
#include <QAction>
#include <QMainWindow>
#include <QApplication>
#include <QtPlugin>
#include <QInputDialog>
#include <QFileDialog>
#include <QMessageBox>
#include <QTimer>
#include <iostream>
#include <fstream>
#include <CGAL/Mesh_optimization_return_code.h>
#include <CGAL/Mesh_3/parameters_defaults.h> // to get default values
// declare the CGAL function
Optimizer_thread* cgal_code_odt_mesh_3(Scene_c3t3_item& c3t3_item,
const double time_limit,
const double convergence_ratio,
const double freeze_ratio,
const int max_iteration_number,
const bool create_new_item);
Optimizer_thread* cgal_code_lloyd_mesh_3(Scene_c3t3_item& c3t3_item,
const double time_limit,
const double convergence_ratio,
const double freeze_ratio,
const int max_iteration_number,
const bool create_new_item);
Optimizer_thread* cgal_code_perturb_mesh_3(Scene_c3t3_item& c3t3_item,
const double time_limit,
const double sliver_bound,
const bool create_new_item);
Optimizer_thread* cgal_code_exude_mesh_3(Scene_c3t3_item& c3t3_item,
const double time_limit,
const double sliver_bound,
const bool create_new_item);
QString translate(CGAL::Mesh_optimization_return_code rc);
// Mesh_3_optimization_plugin class
class Mesh_3_optimization_plugin :
public QObject,
protected Plugin_helper
{
Q_OBJECT
Q_INTERFACES(Plugin_interface)
typedef Plugin_helper Base;
public:
Mesh_3_optimization_plugin();
using Base::init;
virtual void init(QMainWindow*, Scene_interface*, Messages_interface*);
inline virtual QList<QAction*> actions() const;
public slots:
void odt();
void lloyd();
void perturb();
void exude();
void optimization_done(Optimizer_thread* t);
void status_report(QString s);
private:
Scene_c3t3_item* get_c3t3_item() const;
void treat_result(Scene_c3t3_item& source_item, Scene_c3t3_item& result_item,
const QString& name) const;
void launch_thread(Optimizer_thread* thread, const QString& msg);
private:
QAction* actionOdt;
QAction* actionLloyd;
QAction* actionPerturb;
QAction* actionExude;
Messages_interface* msg;
QMessageBox* message_box_;
Scene_c3t3_item* source_item_;
}; // end class Mesh_3_optimization_plugin
Mesh_3_optimization_plugin::
Mesh_3_optimization_plugin()
: actionOdt(NULL)
, actionLloyd(NULL)
, actionPerturb(NULL)
, actionExude(NULL)
, msg(NULL)
, message_box_(NULL)
, source_item_(NULL)
{
}
void
Mesh_3_optimization_plugin::
init(QMainWindow* mainWindow,
Scene_interface* scene_interface,
Messages_interface* msg_interface)
{
this->scene = scene_interface;
this->mw = mainWindow;
// Create menu items
actionOdt = this->getActionFromMainWindow(mw, "actionOdt");
if( NULL != actionOdt )
{
connect(actionOdt, SIGNAL(triggered()), this, SLOT(odt()));
}
actionLloyd = this->getActionFromMainWindow(mw, "actionLloyd");
if( NULL != actionLloyd )
{
connect(actionLloyd, SIGNAL(triggered()), this, SLOT(lloyd()));
}
actionPerturb = this->getActionFromMainWindow(mw, "actionPerturb");
if( NULL != actionPerturb )
{
connect(actionPerturb, SIGNAL(triggered()), this, SLOT(perturb()));
}
actionExude = this->getActionFromMainWindow(mw, "actionExude");
if( NULL != actionExude )
{
connect(actionExude, SIGNAL(triggered()), this, SLOT(exude()));
}
msg = msg_interface;
}
inline
QList<QAction*>
Mesh_3_optimization_plugin::actions() const
{
return QList<QAction*>() << actionOdt << actionLloyd
<< actionPerturb << actionExude;
}
void
Mesh_3_optimization_plugin::odt()
{
// -----------------------------------
// Get c3t3 item
// -----------------------------------
Scene_c3t3_item* item = get_c3t3_item();
if ( NULL == item ) { return; }
// -----------------------------------
// Dialog box
// -----------------------------------
QDialog dialog(mw);
Ui::Smoother_dialog ui;
ui.setupUi(&dialog);
dialog.setWindowTitle(tr("Odt-smoothing parameters"));
connect(ui.buttonBox, SIGNAL(accepted()),
&dialog, SLOT(accept()));
connect(ui.buttonBox, SIGNAL(rejected()),
&dialog, SLOT(reject()));
connect(ui.noTimeLimit, SIGNAL(toggled(bool)),
ui.maxTime, SLOT(setDisabled(bool)));
ui.objectName->setText(item->name());
namespace cgpd = CGAL::parameters::default_values;
ui.convergenceRatio->setValue(cgpd::odt_convergence_ratio);
ui.freezeRatio->setValue(cgpd::odt_freeze_ratio);
int i = dialog.exec();
if(i == QDialog::Rejected)
return;
// 0 means parameter is not considered
const double max_time = ui.noTimeLimit->isChecked() ? 0 : ui.maxTime->value();
const int max_iteration_nb = static_cast<int>(ui.maxIterationNb->value());
const double convergence = ui.convergenceRatio->value();
const double freeze = ui.freezeRatio->value();
const bool create_new_item = ui.createNewItem->isChecked();
// -----------------------------------
// Launch optimization
// -----------------------------------
QApplication::setOverrideCursor(Qt::WaitCursor);
Optimizer_thread* opt_thread = cgal_code_odt_mesh_3(*item,
max_time,
convergence,
freeze,
max_iteration_nb,
create_new_item);
if ( NULL == opt_thread )
{
QApplication::restoreOverrideCursor();
return;
}
source_item_ = item;
launch_thread(opt_thread, "Odt iterations are running...");
QApplication::restoreOverrideCursor();
}
void
Mesh_3_optimization_plugin::lloyd()
{
// -----------------------------------
// Get c3t3 item
// -----------------------------------
Scene_c3t3_item* item = get_c3t3_item();
if ( NULL == item ) { return; }
// -----------------------------------
// Dialog box
// -----------------------------------
QDialog dialog(mw);
Ui::Smoother_dialog ui;
ui.setupUi(&dialog);
dialog.setWindowTitle(tr("Lloyd-smoothing parameters"));
connect(ui.buttonBox, SIGNAL(accepted()),
&dialog, SLOT(accept()));
connect(ui.buttonBox, SIGNAL(rejected()),
&dialog, SLOT(reject()));
connect(ui.noTimeLimit, SIGNAL(toggled(bool)),
ui.maxTime, SLOT(setDisabled(bool)));
ui.objectName->setText(item->name());
namespace cgpd = CGAL::parameters::default_values;
ui.convergenceRatio->setValue(cgpd::lloyd_convergence_ratio);
ui.freezeRatio->setValue(cgpd::lloyd_freeze_ratio);
int i = dialog.exec();
if(i == QDialog::Rejected)
return;
// 0 means parameter is not considered
const double max_time = ui.noTimeLimit->isChecked() ? 0 : ui.maxTime->value();
const int max_iteration_nb = static_cast<int>(ui.maxIterationNb->value());
const double convergence = ui.convergenceRatio->value();
const double freeze = ui.freezeRatio->value();
const bool create_new_item = ui.createNewItem->isChecked();
// -----------------------------------
// Launch optimization
// -----------------------------------
QApplication::setOverrideCursor(Qt::WaitCursor);
Optimizer_thread* opt_thread = cgal_code_lloyd_mesh_3(*item,
max_time,
convergence,
freeze,
max_iteration_nb,
create_new_item);
if ( NULL == opt_thread )
{
QApplication::restoreOverrideCursor();
return;
}
source_item_ = item;
launch_thread(opt_thread, "Lloyd iterations are running...");
QApplication::restoreOverrideCursor();
}
void
Mesh_3_optimization_plugin::perturb()
{
// -----------------------------------
// Get c3t3 item
// -----------------------------------
Scene_c3t3_item* item = get_c3t3_item();
if ( NULL == item ) { return; }
// -----------------------------------
// Dialog box
// -----------------------------------
QDialog dialog(mw);
Ui::LocalOptim_dialog ui;
ui.setupUi(&dialog);
dialog.setWindowTitle(tr("Sliver perturbation parameters"));
connect(ui.buttonBox, SIGNAL(accepted()),
&dialog, SLOT(accept()));
connect(ui.buttonBox, SIGNAL(rejected()),
&dialog, SLOT(reject()));
connect(ui.noTimeLimit, SIGNAL(toggled(bool)),
ui.maxTime, SLOT(setDisabled(bool)));
connect(ui.noBound, SIGNAL(toggled(bool)),
ui.sliverBound, SLOT(setDisabled(bool)));
ui.objectName->setText(item->name());
int i = dialog.exec();
if(i == QDialog::Rejected)
return;
// 0 means parameter is not considered
const double max_time = ui.noTimeLimit->isChecked() ? 0 : ui.maxTime->value();
const double sliver_bound = ui.noBound->isChecked() ? 0 : ui.sliverBound->value();
const bool create_new_item = ui.createNewItem->isChecked();
// -----------------------------------
// Launch optimization
// -----------------------------------
QApplication::setOverrideCursor(Qt::WaitCursor);
Optimizer_thread* opt_thread = cgal_code_perturb_mesh_3(*item,
max_time,
sliver_bound,
create_new_item);
if ( NULL == opt_thread )
{
QApplication::restoreOverrideCursor();
return;
}
source_item_ = item;
launch_thread(opt_thread, "Sliver perturbation is running...");
QApplication::restoreOverrideCursor();
}
void
Mesh_3_optimization_plugin::exude()
{
// -----------------------------------
// Get c3t3 item
// -----------------------------------
Scene_c3t3_item* item = get_c3t3_item();
if ( NULL == item ) { return; }
// -----------------------------------
// Dialog box
// -----------------------------------
QDialog dialog(mw);
Ui::LocalOptim_dialog ui;
ui.setupUi(&dialog);
dialog.setWindowTitle(tr("Sliver exudation parameters"));
connect(ui.buttonBox, SIGNAL(accepted()),
&dialog, SLOT(accept()));
connect(ui.buttonBox, SIGNAL(rejected()),
&dialog, SLOT(reject()));
connect(ui.noTimeLimit, SIGNAL(toggled(bool)),
ui.maxTime, SLOT(setDisabled(bool)));
connect(ui.noBound, SIGNAL(toggled(bool)),
ui.sliverBound, SLOT(setDisabled(bool)));
ui.objectName->setText(item->name());
ui.sliverBound->setValue(25.);
int i = dialog.exec();
if(i == QDialog::Rejected)
return;
// 0 means parameter is not considered
const double max_time = ui.noTimeLimit->isChecked() ? 0 : ui.maxTime->value();
const double sliver_bound = ui.noBound->isChecked() ? 0 : ui.sliverBound->value();
const bool create_new_item = ui.createNewItem->isChecked();
// -----------------------------------
// Launch optimization
// -----------------------------------
QApplication::setOverrideCursor(Qt::WaitCursor);
Optimizer_thread* opt_thread = cgal_code_exude_mesh_3(*item,
max_time,
sliver_bound,
create_new_item);
if ( NULL == opt_thread )
{
QApplication::restoreOverrideCursor();
return;
}
source_item_ = item;
launch_thread(opt_thread, "Sliver exudation is running...");
QApplication::restoreOverrideCursor();
}
Scene_c3t3_item*
Mesh_3_optimization_plugin::
get_c3t3_item() const
{
const Scene_interface::Item_id index = scene->mainSelectionIndex();
Scene_c3t3_item* item = qobject_cast<Scene_c3t3_item*>(scene->item(index));
if ( NULL == item )
{
QMessageBox::warning(mw,tr(""),
tr("Selected object is not a mesh... optimization can't be performed"));
return NULL;
}
if ( NULL == item->data_item() )
{
QMessageBox::critical(mw,tr(""),
tr("Can't perturb: data object has been destroyed !"));
return NULL;
}
return item;
}
void
Mesh_3_optimization_plugin::
treat_result(Scene_c3t3_item& source_item,
Scene_c3t3_item& result_item,
const QString& name) const
{
result_item.setName(tr("%1 [%2]").arg(source_item.name())
.arg(name));
result_item.c3t3_changed();
// If a new item has been created
if ( &source_item != &result_item)
{
const Scene_item::Bbox& bbox = result_item.bbox();
result_item.setPosition((bbox.xmin + bbox.xmax)/2.f,
(bbox.ymin + bbox.ymax)/2.f,
(bbox.zmin + bbox.zmax)/2.f);
result_item.setColor(QColor(59,74,226));
result_item.setRenderingMode(source_item.renderingMode());
result_item.set_data_item(source_item.data_item());
source_item.setVisible(false);
const Scene_interface::Item_id index = scene->mainSelectionIndex();
scene->itemChanged(index);
Scene_interface::Item_id new_item_id = scene->addItem(&result_item);
scene->setSelectedItem(new_item_id);
}
else
{
result_item.update_histogram();
const Scene_interface::Item_id index = scene->mainSelectionIndex();
scene->itemChanged(index);
}
}
void
Mesh_3_optimization_plugin::
optimization_done(Optimizer_thread* thread)
{
CGAL::Mesh_optimization_return_code return_code = thread->return_code();
QString name = thread->optimizer_name();
// Print message in console
QString str = QString("%1 of \"%2\" done in %3s<br>"
"End reason: '%4'<br>")
.arg(name)
.arg(source_item_->name())
.arg(thread->time())
.arg(translate(return_code));
Q_FOREACH( QString param, thread->parameters_log() )
{
str.append(QString("( %1 )<br>").arg(param));
}
msg->information(qPrintable(str));
// Treat new c3t3 item
Scene_c3t3_item* result_item = thread->item();
treat_result( *source_item_, *result_item, name);
// close message box
message_box_->close();
// free memory
delete thread;
}
void
Mesh_3_optimization_plugin::
launch_thread(Optimizer_thread* opt_thread, const QString& window_text)
{
// -----------------------------------
// Create message box with stop button
// -----------------------------------
message_box_ = new QMessageBox(QMessageBox::NoIcon,
"Optimization...",
window_text,
QMessageBox::Cancel,
mw);
message_box_->setDefaultButton(QMessageBox::Cancel);
QAbstractButton* cancelButton = message_box_->button(QMessageBox::Cancel);
cancelButton->setText(tr("Stop"));
QObject::connect(cancelButton, SIGNAL(clicked()),
opt_thread, SLOT(stop()));
message_box_->show();
// -----------------------------------
// Connect main thread to optimization thread and launch optimizer
// -----------------------------------
QObject::connect(opt_thread, SIGNAL(done(Optimizer_thread*)),
this, SLOT(optimization_done(Optimizer_thread*)));
QObject::connect(opt_thread, SIGNAL(status_report(QString)),
this, SLOT(status_report(QString)));
opt_thread->start();
}
void
Mesh_3_optimization_plugin::
status_report(QString str)
{
if ( NULL == message_box_ ) { return; }
message_box_->setInformativeText(str);
}
QString
translate(CGAL::Mesh_optimization_return_code rc)
{
switch (rc)
{
case CGAL::MESH_OPTIMIZATION_UNKNOWN_ERROR: return QString("Unexpected error");
case CGAL::BOUND_REACHED: return QString("Bound reached");
case CGAL::TIME_LIMIT_REACHED: return QString("Time limit reached");
case CGAL::CANT_IMPROVE_ANYMORE: return QString("Can't improve anymore");
case CGAL::CONVERGENCE_REACHED: return QString("Convergence reached");
case CGAL::MAX_ITERATION_NUMBER_REACHED: return QString("Max iteration number reached");
case CGAL::ALL_VERTICES_FROZEN: return QString("All vertices have been frozen");
}
return QString("ERROR");
}
Q_EXPORT_PLUGIN2(Mesh_3_optimization_plugin, Mesh_3_optimization_plugin)
#include "Mesh_3_optimization_plugin.moc"
#endif // CGAL_POLYHEDRON_DEMO_USE_SURFACE_MESHER