#include "Blender.h" #include "Controls.h" #include "ProgressItem.h" #include "BlendRenderItem.h" #include "BlendPathRenderer.h" #include "BlendPathWidget.h" #include "BlendPathSubButton.h" #include "TopoBlender.h" #include "Scheduler.h" #include "Task.h" #include "SynthesisManager.h" #include "ShapeRenderer.h" #include "SchedulerWidget.h" #include "PathEvaluator.h" typedef QVector< QSet > ForcedGroups; Q_DECLARE_METATYPE( ForcedGroups ) Q_DECLARE_METATYPE( ScheduleType ) Blender::Blender(Scene * scene, QString title) : DemoPage(scene,title), m_gcorr(NULL), s_manager(NULL), renderer(NULL), resultViewer(NULL) { this->numSuggestions = 4; this->numInBetweens = 6; this->numSchedules = 300; this->isFiltering = false; this->isSample = true; this->isUniformPath = false; #ifdef QT_DEBUG this->isSample = false; #endif this->graphItemWidth = s->width() * 0.15; setupBlendPathItems(); // Progress bar progress = new ProgressItem("Working..", false, s); // Connections this->connect(this, SIGNAL(keyUpEvent(QKeyEvent*)), SLOT(keyReleased(QKeyEvent*))); this->connect(this, SIGNAL(blendPathsReady()), SLOT(computeBlendPaths())); this->connect(this, SIGNAL(blendPathsDone()), SLOT(blenderDone())); this->connect(this, SIGNAL(blendDone()), SLOT(blenderAllResultsDone())); // Paths evaluation pathsEval = new PathEvaluator(this); progress->connect(pathsEval, SIGNAL(progressChanged(double)), SLOT(setProgress(double))); } void Blender::setupBlendPathItems() { clearResults(); // Create background items for each blend path blendPathWidth = s->width() - (2 * graphItemWidth); blendPathHeight = ((s->height()-200) / numSuggestions); int padding = 3; int totalHeight = numSuggestions * (blendPathHeight + padding); int startY = (s->height() * 0.5 - totalHeight * 0.5) - 25; QColor color( 255, 180, 68, 100 ); // Clear previously set items foreach(QGraphicsProxyWidget * grp, blendPathsWidgets) s->removeItem(grp); blendPathsWidgets.clear(); double w = blendPathWidth; double h = blendPathHeight; for(int i = 0; i < numSuggestions; i++) { double x = 0.5*s->width() - 0.5*w; double y = startY + (i * (blendPathHeight + padding)); BlendPathWidget * widget = new BlendPathWidget(w,h); widget->setBackgroundColor( QColor (255, 255, 255, 5) ); QGraphicsProxyWidget * witem = s->addWidget(widget); witem->setPos(x, y); witem->setVisible(false); witem->setAcceptHoverEvents(true); blendPathsWidgets.push_back(witem); widget->proxy = witem; items.push_back(witem); } // Show path indicators QRectF r0(0,0,graphItemWidth,graphItemWidth); r0.moveTop((s->height() * 0.5) - (r0.height() * 0.5)); QRectF r1 = r0; r1.moveRight(s->width()); QPointF lstart = r0.center() + QPoint(r0.width() * 0.3,0); QPointF rstart = r1.center() - QPoint(r1.width() * 0.3,0); double tension = 0.5; foreach(QGraphicsItem * item, auxItems) s->removeItem(item); auxItems.clear(); for(int i = 0; i < numSuggestions; i++) { QRectF r = blendPathsWidgets[i]->sceneBoundingRect(); QPointF lend = QPointF(r.x(), r.center().y()); QPointF rend = QPointF(r.x() + r.width(), r.center().y()); double lmidX = (lend.x() - lstart.x()) * tension; double rmidX = (rstart.x() - rend.x()) * tension; QVector l_points, r_points; l_points.push_back(lstart); l_points.push_back(lstart + QPointF(lmidX,0)); l_points.push_back(lend - QPointF(lmidX,0)); l_points.push_back(lend); r_points.push_back(rstart); r_points.push_back(rstart - QPointF(rmidX,0)); r_points.push_back(rend + QPointF(rmidX,0)); r_points.push_back(rend); QPainterPath lpath; lpath.moveTo(l_points.at(0)); { int i=1; while (i + 2 < l_points.size()) { lpath.cubicTo(l_points.at(i), l_points.at(i+1), l_points.at(i+2)); i += 3; } } QPainterPath rpath; rpath.moveTo(r_points.at(0)); { int i=1; while (i + 2 < r_points.size()) { rpath.cubicTo(r_points.at(i), r_points.at(i+1), r_points.at(i+2)); i += 3; } } QGraphicsItem * litem = s->addPath(lpath, QPen(color, 1)); QGraphicsItem * ritem = s->addPath(rpath, QPen(color, 1)); litem->setVisible(false); ritem->setVisible(false); auxItems.push_back(litem); auxItems.push_back(ritem); } itemHeight = blendPathHeight; // Add paths navigation buttons QRectF firstGroup = blendPathsWidgets.front()->sceneBoundingRect(); QRectF lastGroup = blendPathsWidgets.back()->sceneBoundingRect(); prevButton = s->addButton(0,0, "prev", colorize( QImage(":/images/arrowUp.png"), QColor(255,153,0), 2 ) ); nextButton = s->addButton(0,0, "next", colorize( QImage(":/images/arrowDown.png"), QColor(255,153,0), 2 ) ); prevButton->setPos(firstGroup.right() - prevButton->boundingRect().width(), firstGroup.top() - padding - prevButton->boundingRect().height()); nextButton->setPos(lastGroup.right() - nextButton->boundingRect().width(), lastGroup.bottom() + padding); prevButton->setVisible(false); nextButton->setVisible(false); auxItems.push_back(prevButton); auxItems.push_back(nextButton); // Connections this->connect(prevButton->widget(), SIGNAL(clicked()), SLOT(showPrevResults())); this->connect(nextButton->widget(), SIGNAL(clicked()), SLOT(showNextResults())); // Results renderer if( renderer ) delete renderer; renderer = new BlendPathRenderer(this, itemHeight); this->connect( renderer, SIGNAL(itemReady(QGraphicsItem*)), SLOT(blendResultDone(QGraphicsItem*)), Qt::DirectConnection ); // Results viewer if( resultViewer ) delete resultViewer; resultViewer = new BlendPathRenderer(this, itemHeight * 2, true ); } void Blender::show() { if(!s->isInputReady()) return; QRectF r0 = s->inputGraphs[0]->boundingRect(); QRectF r1 = s->inputGraphs[1]->boundingRect(); property["r0"] = r0; property["r1"] = r1; // Scale in place QPointF oldCenter0 = r0.center(); QPointF oldCenter1 = r1.center(); double s_factor = graphItemWidth / r0.width(); QMatrix m; m.scale(s_factor,s_factor); r0 = m.mapRect(r0); r1 = m.mapRect(r1); r0.translate(oldCenter0 - r0.center()); r1.translate(oldCenter1 - r1.center()); r0.moveLeft(0); r1.moveRight(s->width()); // Move input shapes to edge of screen QParallelAnimationGroup * animGroup = new QParallelAnimationGroup; animGroup->addAnimation( s->inputGraphs[0]->animateTo(r0) ); animGroup->addAnimation( s->inputGraphs[1]->animateTo(r1) ); animGroup->start( QAbstractAnimation::DeleteWhenStopped ); DemoPage::show(); // Give time for animations to finish QTimer::singleShot(300, this, SLOT(preparePaths())); } void Blender::hide() { if(!s->isInputReady() || !property.contains("r0")) return; foreach(QGraphicsItem * item, auxItems) item->setVisible(false); // Return the two input shapes to original state QParallelAnimationGroup * animGroup = new QParallelAnimationGroup; animGroup->addAnimation( s->inputGraphs[0]->animateTo( property["r0"].toRectF() ) ); animGroup->addAnimation( s->inputGraphs[1]->animateTo( property["r1"].toRectF() ) ); animGroup->start( QAbstractAnimation::DeleteWhenStopped ); DemoPage::hide(); cleanUp(); } void Blender::setGraphCorresponder( GraphCorresponder * graphCorresponder ) { this->m_gcorr = graphCorresponder; } void Blender::schedulePaths( const QSharedPointer & scheduler, const QSharedPointer & blender ) { blendPaths.clear(); blendPaths.resize(numSuggestions); for(int i = 0; i < numSuggestions; i++) { // Shared properties BlendPath bp; bp.source = s->inputGraphs[0]->g; bp.target = s->inputGraphs[1]->g; bp.gcorr = this->m_gcorr; bp.blender = blender; // Per-path properties bp.scheduler = QSharedPointer( scheduler->clone() ); int idx = qMax(0, qMin(allSchedules.size() - 1, (resultsPage * numSuggestions) + i) ); bp.scheduler->setSchedule( allSchedules[ idx ] ); // Add blend path blendPaths[i] = bp; // Connections this->connect(bp.scheduler.data(), SIGNAL(progressChanged(int)), SLOT(pathProgressChanged()), Qt::DirectConnection); } } void Blender::preparePaths() { if(!s->isInputReady() || m_gcorr == NULL) return; emit( blendStarted() ); isFinished = false; // UI and logging { if( isFiltering ) progress->setExtra("Filtering / "); else progress->setExtra("Preparing paths "); progress->show(); qApp->setOverrideCursor(Qt::WaitCursor); qApp->processEvents(); pathsTimer.start(); } // Blending setup m_scheduler = QSharedPointer( new Scheduler ); m_blender = QSharedPointer( new TopoBlender( m_gcorr, m_scheduler.data() ) ); // Synthesis data preparation if( s_manager.isNull() ) { int numSamples = 8000; #ifdef QT_DEBUG numSamples = 100; #endif s_manager = QSharedPointer(new SynthesisManager(m_gcorr, m_scheduler.data(), m_blender.data(), numSamples)); QVariant p_camera; p_camera.setValue( s->camera ); s_manager->property["camera"] = p_camera; // Progress connections progress->connect(s_manager.data(), SIGNAL(progressChanged(double)), SLOT(setProgress(double))); this->connect(s_manager.data(), SIGNAL(synthDataReady()), SLOT(synthDataReady())); } // Apply any user-specified groups ForcedGroups forcedGroups = s->inputGraphs[0]->g->property["forceGroup"].value< ForcedGroups >(); foreach(QSet uids, forcedGroups) { // Retrieve all tasks of the set QVector tasks; foreach(Structure::Node * n, m_scheduler->activeGraph->nodes){ size_t uid = size_t(n->property["mesh"].value< QSharedPointer >().data()); if(uids.contains(uid)) tasks.push_back( n->property["task"].value() ); } // Schedule them together int startTime = m_scheduler->totalExecutionTime(); foreach(Task * t, tasks) startTime = qMin(startTime, t->start); foreach(Task * t, tasks) t->setStart( startTime ); // Clean up m_scheduler->trimTasks(); } /// Generate and sort blend paths: resultsPage = 0; srand(time(NULL)); // Get 'k' schedules sorted by filter measure if( isFiltering ) { allSchedules = pathsEval->filteredSchedules( m_scheduler->manyRandomSchedules( numSchedules ) ); } else { allSchedules = m_scheduler->manyRandomSchedules( numSchedules ); } schedulePaths( m_scheduler, m_blender ); // UI and logging { qApp->restoreOverrideCursor(); progress->startProgress(); progress->setExtra("Generating samples "); emit( message(QString("Paths time [%1 ms]").arg(pathsTimer.elapsed())) ); } synthTimer.start(); // [HEAVY] Generate synthesis data if( isSample ) s_manager->generateSynthesisData(); else emit( s_manager->emitSynthDataReady() ); } void Blender::synthDataReady() { if( property["isOverrideSynth"].toBool() ) return; for(int i = 0; i < numSuggestions; i++) this->disconnect( blendPaths[i].scheduler.data() ); emit( message(QString("Synthesis time [%1 ms]").arg(synthTimer.elapsed())) ); emit( blendPathsReady() ); } void executeJob( const QSharedPointer & scheduler ) { #ifdef QT_DEBUG scheduler->timeStep = 0.3; #endif scheduler->executeAll(); } void Blender::computeBlendPaths() { progress->startProgress(); progress->setExtra("Blend paths "); blendTimer.start(); for(int i = 0; i < blendPaths.size(); i++) jobs.push_back( blendPaths[i].scheduler ); QtConcurrent::run(this, &Blender::computeBlendPathsThread); //computeBlendPathsThread(); } void Blender::computeBlendPathsThread() { #pragma omp parallel for for(int i = 0; i < blendPaths.size(); i++) { executeJob( blendPaths[i].scheduler ); } //QFuture future = QtConcurrent::map(jobs, executeJob); //future.waitForFinished(); emit( blendPathsDone() ); } void Blender::computePath( const int & index ) { blendPaths[index].scheduler->executeAll(); } void Blender::pathProgressChanged() { int curProgress = 0; for(int i = 0; i < blendPaths.size(); i++){ curProgress += blendPaths[i].scheduler->property["progress"].toInt(); } int totalProgress = 100 * blendPaths.size(); progress->setProgress( double(curProgress) / totalProgress ); } void Blender::blenderDone() { // UI and logging { emit( message(QString("Blending time [%1 ms]").arg(blendTimer.elapsed())) ); progress->setExtra("Rendering "); progress->setProgress(0.0); renderTimer.start(); } // For each blend path, render 'k' in-betweens for(int i = 0; i < numSuggestions; i++) { Scheduler * curSchedule = blendPaths[i].scheduler.data(); ScheduleType schedule = curSchedule->getSchedule(); QVector inBetweens; if( isUniformPath ) { inBetweens = curSchedule->topoVaryingInBetweens( numInBetweens ); } else { inBetweens = curSchedule->interestingInBetweens( numInBetweens ); } for(int j = 0; j < numInBetweens; j++) { inBetweens[j]->moveCenterTo( AlphaBlend(inBetweens[j]->property["t"].toDouble(), inBetweens[j]->property["sourceGraphCenter"].value(), inBetweens[j]->property["targetGraphCenter"].value()), true); inBetweens[j]->property["schedule"].setValue( schedule ); renderer->generateItem( inBetweens[j], i, j ); } } } void Blender::mousePress( QGraphicsSceneMouseEvent* mouseEvent ) { if(!visible) return; if( false ) { // Block when controller is clicked foreach(QGraphicsItem * i, s->items(mouseEvent->scenePos())){ QGraphicsProxyWidget * proxy = dynamic_cast(i); if(!proxy) continue; else if(qobject_cast(proxy->widget())) return; } foreach(QGraphicsProxyWidget * proxy, blendPathsWidgets) { if(proxy->sceneBoundingRect().contains(mouseEvent->scenePos())) continue; QGraphicsScene * s = ((BlendPathWidget*)proxy->widget())->scene; s->clearSelection(); } } } void Blender::keyReleased( QKeyEvent* keyEvent ) { // Special keys across all pages: if( keyEvent->key() == Qt::Key_F ) { this->isSample = !this->isSample; emit( message( QString("Sampling toggled to: %1").arg(isSample) ) ); return; } // Regular keys if(!visible) return; // Re-draw results if( keyEvent->key() == Qt::Key_R ){ showResultsPage(); return; } // Sampling type if( keyEvent->key() == Qt::Key_U ){ this->isUniformPath = !this->isUniformPath; emit( message( QString("Uniform sampling on path: %1").arg( this->isUniformPath ) ) ); return; } // EXPERIMENTS: if( keyEvent->key() == Qt::Key_Q ){ // Experiment: path evaluation //pathsEval->evaluatePaths(); //pathsEval->clusterPaths(); pathsEval->test_filtering(); return; } if(keyEvent->key() == Qt::Key_W) { pathsEval->test_topoDistinct(); return; } // Debug render graph function if(keyEvent->key() == Qt::Key_Backspace) { QList allSelected; foreach(QGraphicsProxyWidget * proxy, blendPathsWidgets) allSelected << ((BlendPathWidget*)proxy->widget())->scene->selectedItems(); foreach(QGraphicsItem * item, allSelected) { BlendRenderItem * renderItem = qobject_cast(item->toGraphicsObject()); if(!renderItem) continue; QString filename = QString("testRender_%1.obj").arg(renderItem->property["pathID"].toInt()); s_manager->renderGraph(*renderItem->graph(), filename, false, 6, true); } } // Export all in-betweens on screen if(keyEvent->key() == Qt::Key_A) { for(int i = 0; i < numSuggestions; i++) { for(int j = 0; j < numInBetweens; j++) { QString filename = QString("inbetween_%1_%2.obj").arg( i ).arg( j ); s_manager->renderGraph(*resultItems[i][j]->graph(), filename, false, 6, true, false); } } } // Show full schedule for selected item if(keyEvent->key() == Qt::Key_Space) { QList allSelected; foreach(QGraphicsProxyWidget * proxy, blendPathsWidgets) allSelected << ((BlendPathWidget*)proxy->widget())->scene->selectedItems(); foreach(QGraphicsItem * item, allSelected) { BlendRenderItem * renderItem = qobject_cast(item->toGraphicsObject()); if(!renderItem) continue; int pathID = renderItem->property["pathID"].toInt(); SchedulerWidget * widget = new SchedulerWidget( blendPaths[pathID].scheduler.data() ); widget->setAttribute(Qt::WA_DeleteOnClose); widget->show(); } return; } // Show initial schedule if(keyEvent->key() == Qt::Key_B) { SchedulerWidget * widget = new SchedulerWidget( m_scheduler.data() ); widget->setAttribute(Qt::WA_DeleteOnClose); widget->show(); return; } if( keyEvent->key() == Qt::Key_E ) { emit( showLogWindow() ); emit( message( QString("Filtering [%1] Num schedules [%2]").arg(isFiltering).arg(numSchedules) ) ); return; } // Changing number of results { bool paramChanged = false; if(keyEvent->key() == Qt::Key_Equal) {numSuggestions++; paramChanged = true;} if(keyEvent->key() == Qt::Key_Minus) {numSuggestions--; paramChanged = true;} if(keyEvent->key() == Qt::Key_0) {numInBetweens++; paramChanged = true;} if(keyEvent->key() == Qt::Key_9) {numInBetweens--; paramChanged = true;} if(paramChanged){ setupBlendPathItems(); emit( message( QString("Paths [%1] / In-betweens [%2]").arg(numSuggestions).arg(numInBetweens) ) ); } } } void Blender::blendResultDone(QGraphicsItem* done_item) { BlendRenderItem * item = (BlendRenderItem*) done_item; int pathID = item->property["pathID"].toInt(); int blendIDX = item->property["blendIDX"].toInt(); resultItems[pathID][blendIDX] = QSharedPointer(item); //s->addItem( resultItems[pathID][blendIDX].data() ); QGraphicsScene * scene = ((BlendPathWidget*)blendPathsWidgets[pathID]->widget())->scene; scene->addItem( resultItems[pathID][blendIDX].data() ); this->connect(item, SIGNAL(doubleClicked(BlendRenderItem*)), SLOT(previewItem(BlendRenderItem*))); // Placement QRectF pathRect = blendPathsWidgets[pathID]->boundingRect(); double outterWidth = pathRect.width() / numInBetweens; int delta = 0.5 * (outterWidth - item->boundingRect().width() ); int x = pathRect.x() + (blendIDX * outterWidth) + delta; int y = pathRect.y(); item->setPos(x, y); // UI and logging { int numDone = 0; for(int i = 0; i < numSuggestions; i++) for(int j = 0; j < numInBetweens; j++) if(resultItems[i][j]) numDone++; int N = (numSuggestions * numInBetweens); progress->setProgress( double(numDone) / N ); qApp->processEvents(); if(numDone == N) { isFinished = true; progress->stopProgress(); progress->hide(); emit( message(QString("Render time [%1 ms]").arg(renderTimer.elapsed())) ); emit( blendDone() ); } } } void Blender::blenderAllResultsDone() { // Show UI elements foreach(QGraphicsItem * item, auxItems) item->setVisible(true); // Expand blend sequence near two items for(int i = 0; i < numSuggestions; i++) { QRectF pathRect = blendPathsWidgets[i]->boundingRect(); double outterWidth = (pathRect.width() / numInBetweens); double w = itemHeight * 0.5; double h = itemHeight; for(int j = 0; j < numInBetweens + 1; j++) { double x = pathRect.x() + ((j) * outterWidth) - (w * 0.5); if(j == 0) x = 0; if(j == numInBetweens) x = pathRect.width() - w; addBlendSubItem(x, pathRect.y(), w, h, i, j); } } prevButton->setEnabled(true); nextButton->setEnabled(true); emit( blendFinished() ); } void Blender::addBlendSubItem(double x, double y, double w, double h, int i, int j) { BlendPathSubButton * subItemButton = new BlendPathSubButton(w, h, this, 20); subItemButton->setPos( QPointF(x, y) ); blendSubItems[i][j] = QSharedPointer(subItemButton); blendSubItems[i][j]->property["pathIDX"] = i; double start = 0; double end = 1.0; if(j > 0) start = resultItems[i][j-1]->graph()->property["t"].toDouble(); if(j + 1 < numInBetweens) end = resultItems[i][j]->graph()->property["t"].toDouble(); blendSubItems[i][j]->property["start"].setValue( start ); blendSubItems[i][j]->property["end"].setValue( end ); //s->addItem( blendSubItems[i][j].data() ); QGraphicsScene * scene = ((BlendPathWidget*)blendPathsWidgets[i]->widget())->scene; scene->addItem( blendSubItems[i][j].data() ); } QVector Blender::selectedInBetween() { QVector result; QList allSelected; foreach(QGraphicsProxyWidget * proxy, blendPathsWidgets) allSelected << ((BlendPathWidget*)proxy->widget())->scene->selectedItems(); foreach(QGraphicsItem * item, allSelected) { BlendRenderItem * renderItem = qobject_cast(item->toGraphicsObject()); if(!renderItem) continue; result.push_back( renderItem ); } return result; } void Blender::clearSelectedInBetween() { foreach(QGraphicsProxyWidget * proxy, blendPathsWidgets) { QGraphicsScene * s = ((BlendPathWidget*)proxy->widget())->scene; s->clearSelection(); } } void Blender::exportSelected() { qApp->setOverrideCursor(Qt::WaitCursor); QString msg = "nothing selected."; foreach(BlendRenderItem * renderItem, selectedInBetween()) { Structure::Graph * g = renderItem->graph(); int idx = int(g->property["t"].toDouble() * 100); QString sname = g->property["sourceName"].toString(); QString tname = g->property["targetName"].toString(); QString filename = sname + tname + "." + QString::number(idx); // Create folder QDir d("dataset"); d.mkpath( filename ); // Set it as current QDir::setCurrent( d.absolutePath() + "/" + filename ); // Generate the geometry and export the structure graph s_manager->renderGraph(*g, filename, false, 6, true); // Generate thumbnail QString objFile = d.absolutePath() + "/" + filename + "/" + filename + ".obj"; QString thumbnailFile = d.absolutePath() + "/" + filename + "/" + filename + ".png"; ShapeRenderer::render( objFile ).save( thumbnailFile ); // Send to gallery PropertyMap info; info["Name"] = filename; info["graphFile"] = d.absolutePath() + "/" + filename + "/" + filename + ".xml"; info["thumbFile"] = d.absolutePath() + "/" + filename + "/" + filename + ".png"; info["objFile"] = d.absolutePath() + "/" + filename + "/" + filename + ".obj"; emit( exportShape(filename, info) ); // Restore QDir::setCurrent( d.absolutePath() + "/.." ); } emit( message("Exporting: " + msg) ); qApp->restoreOverrideCursor(); QCursor::setPos(QCursor::pos()); } void Blender::saveJob() { QList allSelected; foreach(QGraphicsProxyWidget * proxy, blendPathsWidgets) allSelected << ((BlendPathWidget*)proxy->widget())->scene->selectedItems(); foreach(QGraphicsItem * item, allSelected) { BlendRenderItem * renderItem = qobject_cast(item->toGraphicsObject()); if(!renderItem) continue; int pathID = renderItem->property["pathID"].toInt(); if(pathID < 0 || pathID > blendPaths.size() - 1) continue; Structure::Graph * g = renderItem->graph(); QString sname = g->property["sourceName"].toString(); QString tname = g->property["targetName"].toString(); QString filename = sname + "." + tname; blendPaths[pathID].scheduler->saveSchedule(filename); QString sGraphName = m_gcorr->sgName(); QString tGraphName = m_gcorr->tgName(); QString graph_names = ( sGraphName + "_" + tGraphName ) + ".job"; QString job_filename = QFileDialog::getSaveFileName(0, tr("Save Job"), 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; m_blender->sg->saveToFile( sgFileName ); QString tRelative = "Target/" + tGraphName + ".xml"; QString tgFileName = jobDir.path() + "/" + tRelative; m_blender->tg->saveToFile( tgFileName ); // Save correspondence file QString correspondRelative = "correspondence.txt"; QString correspondenceFileName = jobDir.path() + "/" + correspondRelative; m_gcorr->saveCorrespondences( correspondenceFileName, true ); // Save the scheduler QString scheduleRelative = "schedule.txt"; QString scheduleFileName = jobDir.path() + "/" + scheduleRelative; blendPaths[pathID].scheduler->saveSchedule( scheduleFileName ); // Save paths & parameters out << sRelative << "\n"; out << tRelative << "\n"; out << correspondRelative << "\n"; out << scheduleRelative << "\n"; out << s_manager->samplesCount << "\t"; out << DIST_RESOLUTION << "\t" << m_scheduler->timeStep << "\n"; out << 7 << "\t" << numInBetweens << "\n"; job_file.close(); // Save samples //s_manager->saveSynthesisData( jobDir.path() + "/" ); } } void Blender::clearResults() { // Clear generated items jobs.clear(); resultItems = QVector< QVector< QSharedPointer > >(numSuggestions, QVector< QSharedPointer >(numInBetweens) ); blendSubItems = QVector< QVector< QSharedPointer > >(numSuggestions, QVector< QSharedPointer >(numInBetweens + 2) ); for(int i = 0; i < blendPathsWidgets.size(); i++) { BlendPathWidget * oldWidget = (BlendPathWidget*)blendPathsWidgets[i]->widget(); oldWidget->buildScene(blendPathWidth, blendPathHeight); } } void Blender::cleanUp() { // Clear results { clearResults(); } // Clean up synthesis data { s_manager.clear(); } // Clean up blending path data { blendPaths.clear(); } } QWidget * Blender::viewer() { return scene()->views().front(); } void Blender::showPrevResults() { prevButton->setEnabled(false); emit( blendStarted() ); if(!blendPaths.size()) return; resultsPage--; if(resultsPage < 0){ resultsPage = 0; return; } showResultsPage(); } void Blender::showNextResults() { nextButton->setEnabled(false); emit( blendStarted() ); if(!blendPaths.size()) return; resultsPage++; if( isFiltering ) { int cutOff = allSchedules.size() * 0.5; // Generate more filtered results if((resultsPage * numSuggestions) > cutOff){ // UI and logging { progress->setExtra("Filtering / "); progress->show(); progress->update(); pathsTimer.restart(); s->update(); qApp->processEvents(); } allSchedules = pathsEval->filteredSchedules( m_scheduler->manyRandomSchedules( numSchedules ) ); resultsPage = 0; // UI and logging { emit( message(QString("Paths filtering time [%1 ms]").arg(pathsTimer.elapsed())) ); } } } showResultsPage(); } void Blender::showResultsPage() { clearResults(); schedulePaths( m_scheduler, m_blender ); // Generate more items emit( blendPathsReady() ); } void Blender::previewItem( BlendRenderItem* item ) { resultViewer->activeGraph = item->graph(); // Placement QRectF viewerRect = resultViewer->geometry(); viewerRect.moveCenter( QCursor::pos() ); resultViewer->setGeometry( viewerRect.toRect() ); resultViewer->show(); } void Blender::emitMessage( QString msg ) { emit( message(msg) ); } void Blender::filterStateChanged( int state ) { this->isFiltering = (state == Qt::Checked); emit( message( QString("Filter state changed: ").arg(isFiltering) ) ); if( this->isFiltering ) numSchedules = 20; }