https://github.com/ialhashim/topo-blend
Revision 39b13612ebd645a65eda854771b517371f2f858a authored by ennetws on 13 March 2015, 18:17:18 UTC, committed by ennetws on 13 March 2015, 18:17:18 UTC
1 parent c702819
Tip revision: 39b13612ebd645a65eda854771b517371f2f858a authored by ennetws on 13 March 2015, 18:17:18 UTC
Create README.md
Create README.md
Tip revision: 39b1361
topo_blend_widget.cpp
#include "topo-blend.h"
#include "topo_blend_widget.h"
#include "ui_topo_blend_widget.h"
#include "ui_animationWidget.h"
#include "landmarks_dialog.h"
#include "StarlabDrawArea.h"
#include "QuickMesh.h"
#include "QuickViewer.h"
#include "QuickGroup.h"
#include <QFileDialog>
#include <QDir>
#include <QListWidgetItem>
#include <QMatrix4x4>
#include "topo-blend.h"
#include "GraphCorresponder.h"
#include "TopoBlender.h"
#include "Scheduler.h"
#include "SchedulerWidget.h"
#include "graphs-manager.h"
#include "correspondence-manager.h"
#include "SynthesisManager.h"
QuickViewer * viewer = NULL;
QString cur_filename;
topo_blend_widget::topo_blend_widget(topoblend * topo_blend, QWidget *parent) : QWidget(parent), ui(new Ui::topo_blend_widget)
{
ui->setupUi(this);
ui->groupBox1->setVisible(false);
this->tb = topo_blend;
// Save / load graphs
topo_blend->g_manager->connect(ui->loadButton, SIGNAL(clicked()), SLOT(loadModel()));
topo_blend->g_manager->connect(ui->saveButton, SIGNAL(clicked()), SLOT(saveModel()));
topo_blend->g_manager->connect(ui->clearButton, SIGNAL(clicked()), SLOT(clearGraphs()));
topo_blend->g_manager->connect(ui->linksButton, SIGNAL(clicked()), SLOT(modifyModel()));
topo_blend->g_manager->connect(ui->alignButton, SIGNAL(clicked()), SLOT(quickAlign()));
topo_blend->g_manager->connect(ui->normalizeButton, SIGNAL(clicked()), SLOT(normalizeAllGraphs()));
// Save / load entire jobs
this->connect(ui->loadJobButton, SIGNAL(clicked()), SLOT(loadJob()));
this->connect(ui->saveJobButton, SIGNAL(clicked()), SLOT(saveJob()));
// Animation widget
//topo_blend->connect(ui->button4, SIGNAL(clicked()), SLOT(currentExperiment()));
//this->connect(ui->animationButton, SIGNAL(clicked()), SLOT(renderViewer()));
// Main blending process
this->connect(ui->blendButton, SIGNAL(clicked()), SLOT(doBlend()), Qt::UniqueConnection);
// Correspondence
this->connect(ui->computeCorrButton, SIGNAL(clicked()), SLOT(loadCorrespondenceModel()));
// Grouping
this->connect(ui->groupButton, SIGNAL(clicked()), SLOT(showGroupingDialog()));
// Synthesis
this->connect(ui->genSynthButton, SIGNAL(clicked()), SLOT(generateSynthesisData()), Qt::UniqueConnection);
topo_blend->s_manager->connect(ui->saveSynthButton, SIGNAL(clicked()), SLOT(saveSynthesisData()));
topo_blend->s_manager->connect(ui->loadSynthButton, SIGNAL(clicked()), SLOT(loadSynthesisData()));
topo_blend->s_manager->connect(ui->reconstructButton, SIGNAL(clicked()), SLOT(reconstructXYZ()));
topo_blend->s_manager->connect(ui->outputCloudButton, SIGNAL(clicked()), SLOT(outputXYZ()));
topo_blend->s_manager->connect(ui->clearSynthButton, SIGNAL(clicked()), SLOT(clear()));
topo_blend->s_manager->connect(ui->synthesisSamplesCount, SIGNAL(valueChanged(int)), SLOT(setSampleCount(int)));
// Model manipulation
this->connect(ui->normalizeModel, SIGNAL(clicked()), SLOT(normalizeModel()));
this->connect(ui->bottomCenterModel, SIGNAL(clicked()), SLOT(bottomCenterModel()));
this->connect(ui->moveModel, SIGNAL(clicked()), SLOT(moveModel()));
this->connect(ui->rotateModel, SIGNAL(clicked()), SLOT(rotateModel()));
this->connect(ui->scaleModel, SIGNAL(clicked()), SLOT(scaleModel()));
this->connect(ui->exportAsOBJ, SIGNAL(clicked()), SLOT(exportAsOBJ()));
// Manipulate parts
this->connect(ui->reverseCurveButton, SIGNAL(clicked()), SLOT(reverseCurve()));
// Populate list
this->updatePartsList();
this->connect(ui->refreshViewButton, SIGNAL(clicked()), SLOT(updatePartsList()));
this->connect(ui->partsList, SIGNAL(itemSelectionChanged()), SLOT(updateVisualization()));
// Visualization & default values
this->connect(ui->vizButtonGroup, SIGNAL(buttonClicked(QAbstractButton*)),SLOT(vizButtonClicked(QAbstractButton*)));
tb->viz_params["showNodes"] = true;
tb->viz_params["showMeshes"] = true;
tb->viz_params["showSamples"] = true;
this->connect(ui->splatSize, SIGNAL(valueChanged(double)), SLOT(splatSizeChanged(double)));
}
QWidget * topo_blend_widget::simpleWidget()
{
return ui->simpleWidget;
}
topo_blend_widget::~topo_blend_widget()
{
delete ui;
}
void topo_blend_widget::doBlend()
{
tb->doBlend();
}
void topo_blend_widget::generateSynthesisData()
{
// Tell synthesis manager about active blend process
tb->s_manager->gcorr = tb->gcoor;
tb->s_manager->scheduler = tb->scheduler;
tb->s_manager->blender = tb->blender;
tb->s_manager->generateSynthesisData();
}
QString topo_blend_widget::loadJobFileName()
{
QString job_filename = QFileDialog::getOpenFileName(0, tr("Load Job"), tb->mainWindow()->settings()->getString("lastUsedDirectory"), tr("Job Files (*.job)"));
if(job_filename.isEmpty()) return "";
// Keep folder active
QFileInfo fileInfo(job_filename);
tb->mainWindow()->settings()->set( "lastUsedDirectory", fileInfo.absolutePath() );
return job_filename;
}
void topo_blend_widget::loadJob()
{
this->loadJobFile( loadJobFileName() );
}
void topo_blend_widget::loadJobFile(QString job_filename)
{
QFile job_file( job_filename );
if (!job_file.open(QIODevice::ReadOnly | QIODevice::Text)) return;
QFileInfo jobFileInfo(job_file.fileName());
QTextStream in(&job_file);
// Job file content
QString sgFileName, tgFileName, correspondenceFileName, scheduleFileName;
int samplesCount;
double gdResolution, timeStep;
int reconLevel, renderCount;
QString curPath = jobFileInfo.absolutePath() + "/";
sgFileName = in.readLine();
tgFileName = in.readLine();
correspondenceFileName = in.readLine();
scheduleFileName = in.readLine();
in >> samplesCount;
in >> gdResolution >> timeStep;
in >> reconLevel >> renderCount;
// Load graphs
tb->graphs.push_back( new Structure::Graph ( curPath + sgFileName ) );
tb->graphs.push_back( new Structure::Graph ( curPath + tgFileName ) );
tb->setSceneBounds();
tb->updateDrawArea();
// Load correspondence
tb->gcoor = tb->c_manager->makeCorresponder();
tb->gcoor->loadCorrespondences( curPath + correspondenceFileName );
tb->gcoor->isReady = true;
// Create TopoBlender
tb->doBlend();
// Load schedule
tb->scheduler->loadSchedule( curPath + scheduleFileName );
// Set parameters
ui->synthesisSamplesCount->setValue( samplesCount );
tb->scheduler->widget->setParams( gdResolution, timeStep, reconLevel, renderCount );
// Sample meshes
//tb->generateSynthesisData();
// Load samples if any
tb->s_manager->gcorr = tb->gcoor;
tb->s_manager->scheduler = tb->scheduler;
tb->s_manager->blender = tb->blender;
tb->s_manager->loadSynthesisData( curPath );
}
void topo_blend_widget::saveJob()
{
topo_blend_widget::saveJob( tb->gcoor, tb->scheduler, tb->blender, tb->s_manager );
}
void topo_blend_widget::saveJob(GraphCorresponder * gcoor, Scheduler * scheduler, TopoBlender * blender, SynthesisManager * s_manager)
{
if(!scheduler) return;
QString sGraphName = gcoor->sgName();
QString tGraphName = gcoor->tgName();
QString graph_names = ( sGraphName + "_" + tGraphName ) + ".job";
QString job_filename = QFileDialog::getSaveFileName(0, tr("Save Job"), tb->mainWindow()->settings()->getString("lastUsedDirectory") + "/" + graph_names, tr("Job Files (*.job)"));
QFile job_file( job_filename );
if (!job_file.open(QIODevice::WriteOnly | QIODevice::Text)) return;
QFileInfo jobFileInfo(job_file.fileName());
QTextStream out(&job_file);
// Create folders
QDir jobDir( jobFileInfo.absolutePath() );
QString sDir = jobDir.path() + "/Source/";
QString tDir = jobDir.path() + "/Target/";
jobDir.mkdir( sDir );
jobDir.mkdir( tDir );
// Save source and target graphs
QString sRelative = "Source/" + sGraphName + ".xml";
QString sgFileName = jobDir.path() + "/" + sRelative;
blender->sg->saveToFile( sgFileName );
QString tRelative = "Target/" + tGraphName + ".xml";
QString tgFileName = jobDir.path() + "/" + tRelative;
blender->tg->saveToFile( tgFileName );
// Save correspondence file
QString correspondRelative = "correspondence.txt";
QString correspondenceFileName = jobDir.path() + "/" + correspondRelative;
gcoor->saveCorrespondences( correspondenceFileName, true );
// Save the scheduler
QString scheduleRelative = "schedule.txt";
QString scheduleFileName = jobDir.path() + "/" + scheduleRelative;
scheduler->saveSchedule( scheduleFileName );
// Save paths & parameters
out << sRelative << "\n";
out << tRelative << "\n";
out << correspondRelative << "\n";
out << scheduleRelative << "\n";
// Synthesis
out << s_manager->samplesCount << "\t";
// Discretization
out << scheduler->widget->gdResolution() << "\t" << scheduler->widget->timeStep() << "\n";
// Reconstruction
out << scheduler->widget->reconLevel() << "\t" << scheduler->widget->renderCount() << "\n";
job_file.close();
// Save samples
s_manager->saveSynthesisData( jobDir.path() + "/" );
}
void topo_blend_widget::showGroupingDialog()
{
if(tb->graphs.isEmpty()) return;
QuickGroup groupingDialog(tb->graphs.front());
tb->connect(&groupingDialog, SIGNAL(updateView()), SLOT(updateDrawArea()));
groupingDialog.exec();
}
void topo_blend_widget::renderViewer()
{
QDialog * d = new QDialog;
d->show();
Ui::AnimationForm aniForm;
aniForm.setupUi(d);
viewer = new QuickViewer();
aniForm.mainLayout->addWidget(viewer);
viewer->makeCurrent();
this->connect(aniForm.button, SIGNAL(clicked()), SLOT(renderAnimation()));
this->connect(aniForm.loadButton, SIGNAL(clicked()), SLOT(loadAnimationModel()));
}
void topo_blend_widget::renderAnimation()
{
QStringList filters, files;
filters << "*.obj" << "*.off";
files = QDir(".").entryList(filters);
int nframes = 0;
foreach(QString filename, files)
{
QString prefix = QFileInfo(cur_filename).baseName();
if(!filename.startsWith(prefix.mid(0,3))) continue;
viewer->m->load(filename, false, false);
viewer->updateGL();
viewer->saveSnapshot(filename + ".png");
nframes++;
}
// Generate GIF using ImageMagick
system(qPrintable( QString("convert -delay %1 -loop 0 seq*.png animation.gif").arg( nframes / 20 ) ));
viewer->setFocus();
}
void topo_blend_widget::loadAnimationModel()
{
viewer->m = new QuickMesh;
cur_filename = QFileDialog::getOpenFileName(this, tr("Open Mesh"), "", tr("Mesh Files (*.obj *.off)"));
viewer->m->load(cur_filename, false, false);
qglviewer::Vec a = qglviewer::Vec(viewer->m->bbmin.x(), viewer->m->bbmin.y(),viewer->m->bbmin.z());
qglviewer::Vec b = qglviewer::Vec(viewer->m->bbmax.x(), viewer->m->bbmax.y(),viewer->m->bbmax.z());
viewer->setSceneBoundingBox(a,b);
viewer->showEntireScene();
viewer->setFocus();
}
void topo_blend_widget::loadCorrespondenceModel()
{
if(tb->graphs.size() != 2) {
qDebug() << "Please load at least 2 graphs.";
return;
}
LandmarksDialog dialog(tb);
dialog.exec();
}
void topo_blend_widget::vizButtonClicked(QAbstractButton* b)
{
Q_UNUSED(b)
tb->viz_params["showNodes"] = ui->showNodes->isChecked();
tb->viz_params["showEdges"] = ui->showEdges->isChecked();
tb->viz_params["showMeshes"] = ui->showMeshes->isChecked();
tb->viz_params["showTasks"] = ui->showTasks->isChecked();
tb->viz_params["showCtrlPts"] = ui->showCtrlPts->isChecked();
tb->viz_params["showCurveFrames"] = ui->showCurveFrames->isChecked();
tb->viz_params["showSamples"] = ui->showSamples->isChecked();
tb->viz_params["isSplatRenderer"] = ui->isSplatsHQ->isChecked();
tb->viz_params["splatSize"] = ui->splatSize->value();
tb->updateDrawArea();
}
void topo_blend_widget::splatSizeChanged(double newSize)
{
tb->viz_params["splatSize"] = newSize;
tb->updateDrawArea();
}
void topo_blend_widget::toggleCheckOption( QString optionName )
{
foreach (QAbstractButton *pButton, ui->vizButtonGroup->buttons()){
if(pButton->objectName() == optionName){
QCheckBox * checkBox = (QCheckBox *)pButton;
checkBox->setChecked( !checkBox->isChecked() );
vizButtonClicked(pButton);
return;
}
}
}
void topo_blend_widget::setCheckOption( QString optionName, bool toValue )
{
foreach (QAbstractButton *pButton, ui->vizButtonGroup->buttons()){
if(pButton->objectName() == optionName){
((QCheckBox *)pButton)->setChecked(toValue);
vizButtonClicked(pButton);
return;
}
}
}
int topo_blend_widget::synthesisSamplesCount()
{
return ui->synthesisSamplesCount->value();
}
void topo_blend_widget::normalizeModel()
{
if(!tb->graphs.size()) return;
tb->graphs.back()->normalize();
tb->setSceneBounds();
tb->updateDrawArea();
}
void topo_blend_widget::bottomCenterModel()
{
if(!tb->graphs.size()) return;
tb->graphs.back()->moveBottomCenterToOrigin();
tb->setSceneBounds();
tb->updateDrawArea();
}
void topo_blend_widget::moveModel()
{
if(!tb->graphs.size()) return;
double s = 0.1;
QMatrix4x4 mat;
mat.translate( ui->movX->value() * s, ui->movY->value() * s, ui->movZ->value() * s );
tb->graphs.back()->transform( mat );
tb->setSceneBounds();
tb->updateDrawArea();
}
void topo_blend_widget::rotateModel()
{
if(!tb->graphs.size()) return;
QMatrix4x4 mat;
mat.rotate( ui->rotX->value(), QVector3D(1,0,0) );
mat.rotate( ui->rotY->value(), QVector3D(0,1,0) );
mat.rotate( ui->rotZ->value(), QVector3D(0,0,1) );
tb->graphs.back()->transform( mat );
tb->setSceneBounds();
tb->updateDrawArea();
}
void topo_blend_widget::scaleModel()
{
if(!tb->graphs.size()) return;
QMatrix4x4 mat;
if( ui->isUniformScale->isChecked() )
{
double s = qMax(ui->scaleX->value(),qMax(ui->scaleY->value(),ui->scaleZ->value()));
mat.scale( s );
}
else
{
mat.scale( ui->scaleX->value(), ui->scaleY->value(), ui->scaleZ->value() );
}
tb->graphs.back()->transform( mat );
tb->setSceneBounds();
tb->updateDrawArea();
}
void topo_blend_widget::exportAsOBJ()
{
if(!tb->graphs.size()) return;
Structure::Graph * g = tb->graphs.back();
QString filename = QFileDialog::getSaveFileName(0, tr("Export OBJ"),
g->property["name"].toString().replace(".xml",".obj"), tr("OBJ Files (*.obj)"));
if(filename.isEmpty()) return;
g->exportAsOBJ( filename );
}
void topo_blend_widget::reverseCurve()
{
if(!tb->graphs.size()) return;
Structure::Graph * g = tb->graphs.back();
foreach(QListWidgetItem * item, ui->partsList->selectedItems())
{
Structure::Node * n = g->getNode(item->text());
if(n->type() == Structure::CURVE)
{
Structure::Curve * curve = (Structure::Curve*) n;
// Flip the selected curve
Array1D_Vector3 ctrlPoint = curve->controlPoints();
Array1D_Real ctrlWeight = curve->controlWeights();
std::reverse(ctrlPoint.begin(), ctrlPoint.end());
std::reverse(ctrlWeight.begin(), ctrlWeight.end());
NURBS::NURBSCurved newCurve(ctrlPoint, ctrlWeight);
curve->curve = newCurve;
// Update the coordinates of its links
foreach( Structure::Link * l, g->getEdges(n->id) )
{
l->setCoord(n->id, inverseCoords( l->getCoord(n->id) ));
}
}
if(n->type() == Structure::SHEET)
{
Structure::Sheet * sheet = (Structure::Sheet*) n;
Array2D_Vector3 ctrlPoint = transpose<Vector3>(sheet->surface.mCtrlPoint);
Array2D_Real ctrlWeight = transpose<Scalar>(sheet->surface.mCtrlWeight);
std::reverse(ctrlPoint.begin(), ctrlPoint.end());
std::reverse(ctrlWeight.begin(), ctrlWeight.end());
int degree = 3;
NURBS::NURBSRectangled newSurface(ctrlPoint, ctrlWeight, degree, degree, false, false, true, true);
sheet->surface = newSurface;
// Update the coordinates of its links
foreach( Structure::Link * l, g->getEdges(n->id) )
{
Array1D_Vector4d oldCoord = l->getCoord(n->id), newCoord;
foreach(Vector4d c, oldCoord) newCoord.push_back(Vector4d(1- c[1], c[0], c[2], c[3]));
l->setCoord(n->id, newCoord);
}
}
}
tb->updateDrawArea();
}
void topo_blend_widget::updatePartsList()
{
if(!tb->graphs.size()) return;
Structure::Graph * g = tb->graphs.back();
// Populate list
foreach(Structure::Node * n, g->nodes)
ui->partsList->addItem(new QListWidgetItem(n->id));
}
void topo_blend_widget::updateVisualization()
{
if(!tb->graphs.size()) return;
Structure::Graph * g = tb->graphs.back();
g->setVisPropertyAll("glow", false);
foreach(QListWidgetItem * item, ui->partsList->selectedItems())
{
Structure::Node * n = g->getNode(item->text());
n->vis_property["glow"] = true;
}
tb->updateDrawArea();
}
void topo_blend_widget::setSynthSamplesCount( int samplesCount )
{
ui->synthesisSamplesCount->setValue( samplesCount );
}
void topo_blend_widget::addTab( QWidget * widget )
{
ui->tabWidget->insertTab(1, widget, widget->windowTitle());
}
Computing file changes ...