diff --git a/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkMovieMaker.dox b/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkMovieMaker.dox index 93188462b8..fb341641ed 100644 --- a/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkMovieMaker.dox +++ b/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkMovieMaker.dox @@ -1,56 +1,65 @@ /** \page org_mitk_gui_qt_moviemaker The Movie Maker Plugin \imageMacro{QmitkMovieMaker_Icon.png,"Icon of the Movie Maker Plugin.",2.00} \tableofcontents \section org_mitk_gui_qt_moviemakerOverview Overview The Movie Maker View allows you to create basic animations of your scene and to record them to video files. Individual animations are arranged in a timeline and can be played back sequential or in parallel. The Movie Maker View uses external FFmpeg/Libav command line utilities to write compressed video files. You have to manually install either FFmpeg or Libav and set the corresponding path in "External Programs" in the MITK Workbench Preferences (Ctrl+P) in order to record your movies to video files. \imageMacro{QmitkMovieMaker_Preferences.png,"The External Programs preferences page.",12.00} \section org_mitk_gui_qt_moviemakerUsage Usage \imageMacro{QmitkMovieMaker_MovieMakerView.png,"The Movie Maker View.",16.00} To create a movie you have to add an animation to the timeline by clicking the "Add animation" button. You can choose between the available types of animations, e.g., Orbit or Slice. The timeline surrounding bottons allow you to arrange, remove, or add further animations to your movie. Each animation can be set to either begin with the previous animation, i.e., run in parallel, or to start after the previous animation, i.e., run sequential. In combination with delays, rather complex animation arrangements are possible. To set animation specific parameters, select the corresponding animation in the timeline first. You can play back, pause and stop your movie with the according controls at the bottom of the Movie Maker View. Click the "Record" button to finally record your movie to a video file with the specified number of frames per second. You have to choose the render window which you want to record. \subsection org_mitk_gui_qt_moviemakerOrbitUsage Orbit Animation The Orbit animation rotates the camera in the 3D window around the scene. Align the camera directly in the 3D window and enter the number of degrees for the orbitting. You usually do not need to adjust the "Start angle" setting - leave it at 180 degrees. If you are planning to have a specific view in the middle of your movie you can play the movie and pause it at the specific frame of interest. Adjust the camera in the 3D window and restart the animation. \imageMacro{QmitkMovieMaker_Orbit.png,"The Orbit animation.",12.00} \subsection org_mitk_gui_qt_moviemakerSliceUsage Slice Animation The Slice animation slices through an image. You can choose the image plane (axial, sagittal, or coronal), as well as the start and end points of the slicing. Use the image navigator in the bottom left of the Workbench to get an idea of the desired values. Check "Reverse" in order to slice from the higher slice number to the lower slice number. \imageMacro{QmitkMovieMaker_Slice.png,"The Slice animation.",12.00} +\subsection org_mitk_gui_qt_moviemakerTimeUsage Time Animation + +The Time animation steps through the individual time steps of the current scene. +You can specify the range of the animated time steps. +Use the image navigator in the bottom left of the Workbench to get an idea of the desired values. +Check "Reverse" in order to step from later time steps to previous time steps. + +\imageMacro{QmitkMovieMaker_Time.gif,"The Time animation.",12.00} + */ diff --git a/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkMovieMaker_Time.gif b/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkMovieMaker_Time.gif new file mode 100644 index 0000000000..0b78372955 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkMovieMaker_Time.gif differ diff --git a/Plugins/org.mitk.gui.qt.moviemaker/files.cmake b/Plugins/org.mitk.gui.qt.moviemaker/files.cmake index 11d7677e23..184872f9d9 100644 --- a/Plugins/org.mitk.gui.qt.moviemaker/files.cmake +++ b/Plugins/org.mitk.gui.qt.moviemaker/files.cmake @@ -1,53 +1,57 @@ set(SRC_CPP_FILES ) set(INTERNAL_CPP_FILES QmitkAnimationItem.cpp QmitkAnimationItemDelegate.cpp QmitkAnimationWidget.cpp QmitkFFmpegWriter.cpp QmitkMovieMakerView.cpp QmitkOrbitAnimationItem.cpp QmitkOrbitAnimationWidget.cpp QmitkSliceAnimationItem.cpp QmitkSliceAnimationWidget.cpp + QmitkTimeSliceAnimationItem.cpp + QmitkTimeSliceAnimationWidget.cpp mitkMovieMakerPluginActivator.cpp QmitkScreenshotMaker.cpp ) set(UI_FILES src/internal/QmitkMovieMakerView.ui src/internal/QmitkOrbitAnimationWidget.ui src/internal/QmitkSliceAnimationWidget.ui + src/internal/QmitkTimeSliceAnimationWidget.ui src/internal/QmitkScreenshotMakerControls.ui ) set(MOC_H_FILES src/internal/mitkMovieMakerPluginActivator.h src/internal/QmitkAnimationItemDelegate.h src/internal/QmitkAnimationWidget.h src/internal/QmitkFFmpegWriter.h src/internal/QmitkMovieMakerView.h src/internal/QmitkOrbitAnimationWidget.h src/internal/QmitkSliceAnimationWidget.h + src/internal/QmitkTimeSliceAnimationWidget.h src/internal/QmitkScreenshotMaker.h ) set(CACHED_RESOURCE_FILES resources/camera-video.png resources/screenshot_maker.png plugin.xml ) set(QRC_FILES resources/QmitkMovieMaker.qrc ) foreach(file ${SRC_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/${file}) endforeach(file ${SRC_CPP_FILES}) foreach(file ${INTERNAL_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/internal/${file}) endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkMovieMakerView.cpp b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkMovieMakerView.cpp index 04a729e901..e03aea6d7c 100644 --- a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkMovieMakerView.cpp +++ b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkMovieMakerView.cpp @@ -1,684 +1,690 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkAnimationItemDelegate.h" #include "QmitkFFmpegWriter.h" #include "QmitkMovieMakerView.h" #include "QmitkOrbitAnimationItem.h" #include "QmitkOrbitAnimationWidget.h" #include "QmitkSliceAnimationItem.h" #include "QmitkSliceAnimationWidget.h" +#include "QmitkTimeSliceAnimationWidget.h" +#include "QmitkTimeSliceAnimationItem.h" #include #include #include #include #include #include #include #include static QmitkAnimationItem* CreateDefaultAnimation(const QString& widgetKey) { if (widgetKey == "Orbit") return new QmitkOrbitAnimationItem; if (widgetKey == "Slice") return new QmitkSliceAnimationItem; + if (widgetKey == "Time") + return new QmitkTimeSliceAnimationItem; + return NULL; } static QString GetFFmpegPath() { berry::IPreferencesService::Pointer preferencesService = berry::Platform::GetServiceRegistry().GetServiceById(berry::IPreferencesService::ID); berry::IPreferences::Pointer preferences = preferencesService->GetSystemPreferences()->Node("/org.mitk.gui.qt.ext.externalprograms"); return QString::fromStdString(preferences->Get("ffmpeg", "")); } static unsigned char* ReadPixels(vtkRenderWindow* renderWindow, int x, int y, int width, int height) { if (renderWindow == NULL) return NULL; unsigned char* frame = new unsigned char[width * height * 3]; renderWindow->MakeCurrent(); glReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, frame); return frame; } const std::string QmitkMovieMakerView::VIEW_ID = "org.mitk.views.moviemaker"; QmitkMovieMakerView::QmitkMovieMakerView() : m_FFmpegWriter(NULL), m_Ui(new Ui::QmitkMovieMakerView), m_AnimationModel(NULL), m_AddAnimationMenu(NULL), m_RecordMenu(NULL), m_Timer(NULL), m_TotalDuration(0.0), m_NumFrames(0), m_CurrentFrame(0) { } QmitkMovieMakerView::~QmitkMovieMakerView() { } void QmitkMovieMakerView::CreateQtPartControl(QWidget* parent) { m_FFmpegWriter = new QmitkFFmpegWriter(parent); m_Ui->setupUi(parent); this->InitializeAnimationWidgets(); this->InitializeAnimationTreeViewWidgets(); this->InitializePlaybackAndRecordWidgets(); this->InitializeTimer(parent); m_Ui->animationWidgetGroupBox->setVisible(false); } void QmitkMovieMakerView::InitializeAnimationWidgets() { m_AnimationWidgets["Orbit"] = new QmitkOrbitAnimationWidget; m_AnimationWidgets["Slice"] = new QmitkSliceAnimationWidget; + m_AnimationWidgets["Time"] = new QmitkTimeSliceAnimationWidget; Q_FOREACH(QWidget* widget, m_AnimationWidgets.values()) { if (widget != NULL) { widget->setVisible(false); m_Ui->animationWidgetGroupBoxLayout->addWidget(widget); } } this->ConnectAnimationWidgets(); } void QmitkMovieMakerView::InitializeAnimationTreeViewWidgets() { this->InitializeAnimationModel(); this->InitializeAddAnimationMenu(); this->ConnectAnimationTreeViewWidgets(); } void QmitkMovieMakerView::InitializePlaybackAndRecordWidgets() { this->InitializeRecordMenu(); this->ConnectPlaybackAndRecordWidgets(); } void QmitkMovieMakerView::InitializeAnimationModel() { m_AnimationModel = new QStandardItemModel(m_Ui->animationTreeView); m_AnimationModel->setHorizontalHeaderLabels(QStringList() << "Animation" << "Timeline"); m_Ui->animationTreeView->setModel(m_AnimationModel); m_Ui->animationTreeView->setItemDelegate(new QmitkAnimationItemDelegate(m_Ui->animationTreeView)); } void QmitkMovieMakerView::InitializeAddAnimationMenu() { m_AddAnimationMenu = new QMenu(m_Ui->addAnimationButton); Q_FOREACH(const QString& key, m_AnimationWidgets.keys()) { m_AddAnimationMenu->addAction(key); } } void QmitkMovieMakerView::InitializeRecordMenu() { typedef QPair PairOfStrings; m_RecordMenu = new QMenu(m_Ui->recordButton); QVector renderWindows; renderWindows.push_back(qMakePair(QString("Axial"), QString("stdmulti.widget1"))); renderWindows.push_back(qMakePair(QString("Sagittal"), QString("stdmulti.widget2"))); renderWindows.push_back(qMakePair(QString("Coronal"), QString("stdmulti.widget3"))); renderWindows.push_back(qMakePair(QString("3D"), QString("stdmulti.widget4"))); Q_FOREACH(const PairOfStrings& renderWindow, renderWindows) { QAction* action = new QAction(m_RecordMenu); action->setText(renderWindow.first); action->setData(renderWindow.second); m_RecordMenu->addAction(action); } } void QmitkMovieMakerView::InitializeTimer(QWidget* parent) { m_Timer = new QTimer(parent); this->OnFPSSpinBoxValueChanged(m_Ui->fpsSpinBox->value()); this->ConnectTimer(); } void QmitkMovieMakerView::ConnectAnimationTreeViewWidgets() { this->connect(m_AnimationModel, SIGNAL(rowsInserted(const QModelIndex&, int, int)), this, SLOT(OnAnimationTreeViewRowsInserted(const QModelIndex&, int, int))); this->connect(m_AnimationModel, SIGNAL(rowsRemoved(const QModelIndex&, int, int)), this, SLOT(OnAnimationTreeViewRowsRemoved(const QModelIndex&, int, int))); this->connect(m_Ui->animationTreeView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this, SLOT(OnAnimationTreeViewSelectionChanged(const QItemSelection&, const QItemSelection&))); this->connect(m_Ui->moveAnimationUpButton, SIGNAL(clicked()), this, SLOT(OnMoveAnimationUpButtonClicked())); this->connect(m_Ui->moveAnimationDownButton, SIGNAL(clicked()), this, SLOT(OnMoveAnimationDownButtonClicked())); this->connect(m_Ui->addAnimationButton, SIGNAL(clicked()), this, SLOT(OnAddAnimationButtonClicked())); this->connect(m_Ui->removeAnimationButton, SIGNAL(clicked()), this, SLOT(OnRemoveAnimationButtonClicked())); } void QmitkMovieMakerView::ConnectAnimationWidgets() { this->connect(m_Ui->startComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnStartComboBoxCurrentIndexChanged(int))); this->connect(m_Ui->durationSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnDurationSpinBoxValueChanged(double))); this->connect(m_Ui->delaySpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnDelaySpinBoxValueChanged(double))); } void QmitkMovieMakerView::ConnectPlaybackAndRecordWidgets() { this->connect(m_Ui->playButton, SIGNAL(toggled(bool)), this, SLOT(OnPlayButtonToggled(bool))); this->connect(m_Ui->stopButton, SIGNAL(clicked()), this, SLOT(OnStopButtonClicked())); this->connect(m_Ui->recordButton, SIGNAL(clicked()), this, SLOT(OnRecordButtonClicked())); this->connect(m_Ui->fpsSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnFPSSpinBoxValueChanged(int))); } void QmitkMovieMakerView::ConnectTimer() { this->connect(m_Timer, SIGNAL(timeout()), this, SLOT(OnTimerTimeout())); } void QmitkMovieMakerView::SetFocus() { m_Ui->addAnimationButton->setFocus(); } void QmitkMovieMakerView::OnMoveAnimationUpButtonClicked() { const QItemSelection selection = m_Ui->animationTreeView->selectionModel()->selection(); if (!selection.isEmpty()) { const int selectedRow = selection[0].top(); if (selectedRow > 0) m_AnimationModel->insertRow(selectedRow - 1, m_AnimationModel->takeRow(selectedRow)); } this->CalculateTotalDuration(); } void QmitkMovieMakerView::OnMoveAnimationDownButtonClicked() { const QItemSelection selection = m_Ui->animationTreeView->selectionModel()->selection(); if (!selection.isEmpty()) { const int rowCount = m_AnimationModel->rowCount(); const int selectedRow = selection[0].top(); if (selectedRow < rowCount - 1) m_AnimationModel->insertRow(selectedRow + 1, m_AnimationModel->takeRow(selectedRow)); } this->CalculateTotalDuration(); } void QmitkMovieMakerView::OnAddAnimationButtonClicked() { QAction* action = m_AddAnimationMenu->exec(QCursor::pos()); if (action != NULL) { const QString widgetKey = action->text(); m_AnimationModel->appendRow(QList() << new QStandardItem(widgetKey) << CreateDefaultAnimation(widgetKey)); m_Ui->playbackAndRecordingGroupBox->setEnabled(true); } } void QmitkMovieMakerView::OnPlayButtonToggled(bool checked) { if (checked) { m_Ui->playButton->setIcon(QIcon(":/org_mitk_icons/icons/tango/scalable/actions/media-playback-pause.svg")); m_Ui->playButton->repaint(); m_Timer->start(static_cast(1000.0 / m_Ui->fpsSpinBox->value())); } else { m_Timer->stop(); m_Ui->playButton->setIcon(QIcon(":/org_mitk_icons/icons/tango/scalable/actions/media-playback-start.svg")); m_Ui->playButton->repaint(); } } void QmitkMovieMakerView::OnStopButtonClicked() { m_Ui->playButton->setChecked(false); m_Ui->stopButton->setEnabled(false); m_CurrentFrame = 0; this->RenderCurrentFrame(); } void QmitkMovieMakerView::OnRecordButtonClicked() // TODO: Refactor { const QString ffmpegPath = GetFFmpegPath(); if (ffmpegPath.isEmpty()) { QMessageBox::information(NULL, "Movie Maker", "

Set path to FFmpeg1 or Libav2 (avconv) in preferences (Window -> Preferences... (Ctrl+P) -> External Programs) to be able to record your movies to video files.

" "

If you are using Linux, chances are good that either FFmpeg or Libav is included in the official package repositories.

" "

[1] Download FFmpeg from ffmpeg.org
" "[2] Download Libav from libav.org

"); return; } m_FFmpegWriter->SetFFmpegPath(GetFFmpegPath()); QAction* action = m_RecordMenu->exec(QCursor::pos()); if (action == NULL) return; vtkRenderWindow* renderWindow = mitk::BaseRenderer::GetRenderWindowByName(action->data().toString().toStdString()); if (renderWindow == NULL) return; const int border = 3; const int x = border; const int y = border; int width = renderWindow->GetSize()[0] - border * 2; int height = renderWindow->GetSize()[1] - border * 2; if (width & 1) --width; if (height & 1) --height; if (width < 16 || height < 16) return; m_FFmpegWriter->SetSize(width, height); m_FFmpegWriter->SetFramerate(m_Ui->fpsSpinBox->value()); QString saveFileName = QFileDialog::getSaveFileName(NULL, "Specify a filename", "", "Movie (*.mp4)"); if (saveFileName.isEmpty()) return; if(!saveFileName.endsWith(".mp4")) saveFileName += ".mp4"; m_FFmpegWriter->SetOutputPath(saveFileName); try { m_FFmpegWriter->Start(); for (m_CurrentFrame = 0; m_CurrentFrame < m_NumFrames; ++m_CurrentFrame) { this->RenderCurrentFrame(); renderWindow->MakeCurrent(); unsigned char* frame = ReadPixels(renderWindow, x, y, width, height); m_FFmpegWriter->WriteFrame(frame); delete[] frame; } m_FFmpegWriter->Stop(); m_CurrentFrame = 0; this->RenderCurrentFrame(); } catch (const mitk::Exception& exception) { m_CurrentFrame = 0; this->RenderCurrentFrame(); QMessageBox::critical(NULL, "Movie Maker", exception.GetDescription()); } } void QmitkMovieMakerView::OnRemoveAnimationButtonClicked() { const QItemSelection selection = m_Ui->animationTreeView->selectionModel()->selection(); if (!selection.isEmpty()) m_AnimationModel->removeRow(selection[0].top()); } void QmitkMovieMakerView::OnAnimationTreeViewRowsInserted(const QModelIndex& parent, int start, int) { this->CalculateTotalDuration(); m_Ui->animationTreeView->selectionModel()->select( m_AnimationModel->index(start, 0, parent), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); } void QmitkMovieMakerView::OnAnimationTreeViewRowsRemoved(const QModelIndex&, int, int) { this->CalculateTotalDuration(); this->UpdateWidgets(); } void QmitkMovieMakerView::OnAnimationTreeViewSelectionChanged(const QItemSelection&, const QItemSelection&) { this->UpdateWidgets(); } void QmitkMovieMakerView::OnStartComboBoxCurrentIndexChanged(int index) { QmitkAnimationItem* item = this->GetSelectedAnimationItem(); if (item != NULL) { item->SetStartWithPrevious(index); this->RedrawTimeline(); this->CalculateTotalDuration(); } } void QmitkMovieMakerView::OnDurationSpinBoxValueChanged(double value) { QmitkAnimationItem* item = this->GetSelectedAnimationItem(); if (item != NULL) { item->SetDuration(value); this->RedrawTimeline(); this->CalculateTotalDuration(); } } void QmitkMovieMakerView::OnDelaySpinBoxValueChanged(double value) { QmitkAnimationItem* item = this->GetSelectedAnimationItem(); if (item != NULL) { item->SetDelay(value); this->RedrawTimeline(); this->CalculateTotalDuration(); } } void QmitkMovieMakerView::OnFPSSpinBoxValueChanged(int value) { this->CalculateTotalDuration(); m_Timer->setInterval(static_cast(1000.0 / value)); } void QmitkMovieMakerView::OnTimerTimeout() { this->RenderCurrentFrame(); m_CurrentFrame = std::min(m_NumFrames, m_CurrentFrame + 1); if (m_CurrentFrame >= m_NumFrames) { m_Ui->playButton->setChecked(false); m_CurrentFrame = 0; this->RenderCurrentFrame(); } m_Ui->stopButton->setEnabled(m_CurrentFrame != 0); } void QmitkMovieMakerView::RenderCurrentFrame() { typedef QPair AnimationInterpolationFactorPair; const double deltaT = m_TotalDuration / (m_NumFrames - 1); const QVector activeAnimations = this->GetActiveAnimations(m_CurrentFrame * deltaT); Q_FOREACH(const AnimationInterpolationFactorPair& animation, activeAnimations) { const QVector nextActiveAnimations = this->GetActiveAnimations((m_CurrentFrame + 1) * deltaT); bool lastFrameForAnimation = true; Q_FOREACH(const AnimationInterpolationFactorPair& nextAnimation, nextActiveAnimations) { if (nextAnimation.first == animation.first) { lastFrameForAnimation = false; break; } } animation.first->Animate(!lastFrameForAnimation ? animation.second : 1.0); } mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll(); } void QmitkMovieMakerView::UpdateWidgets() { const QItemSelection selection = m_Ui->animationTreeView->selectionModel()->selection(); if (selection.isEmpty()) { m_Ui->moveAnimationUpButton->setEnabled(false); m_Ui->moveAnimationDownButton->setEnabled(false); m_Ui->removeAnimationButton->setEnabled(false); m_Ui->playbackAndRecordingGroupBox->setEnabled(false); this->HideCurrentAnimationWidget(); } else { const int rowCount = m_AnimationModel->rowCount(); const int selectedRow = selection[0].top(); m_Ui->moveAnimationUpButton->setEnabled(rowCount > 1 && selectedRow != 0); m_Ui->moveAnimationDownButton->setEnabled(rowCount > 1 && selectedRow < rowCount - 1); m_Ui->removeAnimationButton->setEnabled(true); m_Ui->playbackAndRecordingGroupBox->setEnabled(true); this->ShowAnimationWidget(dynamic_cast(m_AnimationModel->item(selectedRow, 1))); } this->UpdateAnimationWidgets(); } void QmitkMovieMakerView::UpdateAnimationWidgets() { QmitkAnimationItem* item = this->GetSelectedAnimationItem(); if (item != NULL) { m_Ui->startComboBox->setCurrentIndex(item->GetStartWithPrevious()); m_Ui->durationSpinBox->setValue(item->GetDuration()); m_Ui->delaySpinBox->setValue(item->GetDelay()); m_Ui->animationGroupBox->setEnabled(true); } else { m_Ui->animationGroupBox->setEnabled(false); } } void QmitkMovieMakerView::HideCurrentAnimationWidget() { if (m_Ui->animationWidgetGroupBox->isVisible()) { m_Ui->animationWidgetGroupBox->setVisible(false); int numWidgets = m_Ui->animationWidgetGroupBoxLayout->count(); for (int i = 0; i < numWidgets; ++i) m_Ui->animationWidgetGroupBoxLayout->itemAt(i)->widget()->setVisible(false); } } void QmitkMovieMakerView::ShowAnimationWidget(QmitkAnimationItem* animationItem) { this->HideCurrentAnimationWidget(); if (animationItem == NULL) return; const QString widgetKey = animationItem->GetWidgetKey(); QmitkAnimationWidget* animationWidget = NULL; if (m_AnimationWidgets.contains(widgetKey)) { animationWidget = m_AnimationWidgets[widgetKey]; if (animationWidget != NULL) { m_Ui->animationWidgetGroupBox->setTitle(widgetKey); animationWidget->SetAnimationItem(animationItem); animationWidget->setVisible(true); } } m_Ui->animationWidgetGroupBox->setVisible(animationWidget != NULL); } void QmitkMovieMakerView::RedrawTimeline() { if (m_AnimationModel->rowCount() > 1) { m_Ui->animationTreeView->dataChanged( m_AnimationModel->index(0, 1), m_AnimationModel->index(m_AnimationModel->rowCount() - 1, 1)); } } QmitkAnimationItem* QmitkMovieMakerView::GetSelectedAnimationItem() const { const QItemSelection selection = m_Ui->animationTreeView->selectionModel()->selection(); return !selection.isEmpty() ? dynamic_cast(m_AnimationModel->item(selection[0].top(), 1)) : NULL; } void QmitkMovieMakerView::CalculateTotalDuration() { const int rowCount = m_AnimationModel->rowCount(); double totalDuration = 0.0; double previousStart = 0.0; for (int i = 0; i < rowCount; ++i) { QmitkAnimationItem* item = dynamic_cast(m_AnimationModel->item(i, 1)); if (item == NULL) continue; if (item->GetStartWithPrevious()) { totalDuration = std::max(totalDuration, previousStart + item->GetDelay() + item->GetDuration()); } else { previousStart = totalDuration; totalDuration += item->GetDelay() + item->GetDuration(); } } m_TotalDuration = totalDuration; // TODO totalDuration == 0 m_NumFrames = static_cast(totalDuration * m_Ui->fpsSpinBox->value()); // TODO numFrames < 2 } QVector > QmitkMovieMakerView::GetActiveAnimations(double t) const { const int rowCount = m_AnimationModel->rowCount(); QVector > activeAnimations; double totalDuration = 0.0; double previousStart = 0.0; for (int i = 0; i < rowCount; ++i) { QmitkAnimationItem* item = dynamic_cast(m_AnimationModel->item(i, 1)); if (item == NULL) continue; if (item->GetDuration() > 0.0) { double start = item->GetStartWithPrevious() ? previousStart + item->GetDelay() : totalDuration + item->GetDelay(); if (start <= t && t <= start + item->GetDuration()) activeAnimations.push_back(qMakePair(item, (t - start) / item->GetDuration())); } if (item->GetStartWithPrevious()) { totalDuration = std::max(totalDuration, previousStart + item->GetDelay() + item->GetDuration()); } else { previousStart = totalDuration; totalDuration += item->GetDelay() + item->GetDuration(); } } return activeAnimations; } diff --git a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkTimeSliceAnimationItem.cpp b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkTimeSliceAnimationItem.cpp new file mode 100644 index 0000000000..8c84cc8fca --- /dev/null +++ b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkTimeSliceAnimationItem.cpp @@ -0,0 +1,74 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "QmitkTimeSliceAnimationItem.h" +#include + +QmitkTimeSliceAnimationItem::QmitkTimeSliceAnimationItem(int from, int to, bool reverse, double duration, double delay, bool startWithPrevious) + : QmitkAnimationItem("Time", duration, delay, startWithPrevious) +{ + this->SetFrom(from); + this->SetTo(to); + this->SetReverse(reverse); +} + +QmitkTimeSliceAnimationItem::~QmitkTimeSliceAnimationItem() +{ +} + +int QmitkTimeSliceAnimationItem::GetFrom() const +{ + return this->data(FromRole).toInt(); +} + +void QmitkTimeSliceAnimationItem::SetFrom(int from) +{ + this->setData(from, FromRole); +} + +int QmitkTimeSliceAnimationItem::GetTo() const +{ + return this->data(ToRole).toInt(); +} + +void QmitkTimeSliceAnimationItem::SetTo(int to) +{ + this->setData(to, ToRole); +} + +bool QmitkTimeSliceAnimationItem::GetReverse() const +{ + return this->data(ReverseRole).toBool(); +} + +void QmitkTimeSliceAnimationItem::SetReverse(bool reverse) +{ + this->setData(reverse, ReverseRole); +} + +void QmitkTimeSliceAnimationItem::Animate(double s) +{ + mitk::Stepper* stepper = mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetTime(); + + if (stepper == NULL) + return; + + int newPos = this->GetReverse() + ? this->GetTo() - static_cast((this->GetTo() - this->GetFrom()) * s) + : this->GetFrom() + static_cast((this->GetTo() - this->GetFrom()) * s); + + stepper->SetPos(static_cast(newPos)); +} diff --git a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkTimeSliceAnimationItem.h b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkTimeSliceAnimationItem.h new file mode 100644 index 0000000000..916f74ae20 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkTimeSliceAnimationItem.h @@ -0,0 +1,40 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef QmitkTimeSliceAnimationItem_h +#define QmitkTimeSliceAnimationItem_h + +#include "QmitkAnimationItem.h" + +class QmitkTimeSliceAnimationItem : public QmitkAnimationItem +{ +public: + explicit QmitkTimeSliceAnimationItem(int from = 0, int to = 0, bool reverse = false, double duration = 2.0, double delay = 0.0, bool startWithPrevious = false); + virtual ~QmitkTimeSliceAnimationItem(); + + int GetFrom() const; + void SetFrom(int from); + + int GetTo() const; + void SetTo(int to); + + bool GetReverse() const; + void SetReverse(bool reverse); + + void Animate(double s); +}; + +#endif diff --git a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkTimeSliceAnimationWidget.cpp b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkTimeSliceAnimationWidget.cpp new file mode 100644 index 0000000000..189f4eda95 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkTimeSliceAnimationWidget.cpp @@ -0,0 +1,102 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "QmitkTimeSliceAnimationItem.h" +#include "QmitkTimeSliceAnimationWidget.h" +#include +#include +#include +#include + +static int GetNumberOfSlices() +{ + mitk::Stepper* stepper = mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetTime(); + + if (stepper != NULL) + return std::max(1, static_cast(stepper->GetSteps())); + + return 1; +} + +QmitkTimeSliceAnimationWidget::QmitkTimeSliceAnimationWidget(QWidget* parent) + : QmitkAnimationWidget(parent), + m_Ui(new Ui::QmitkTimeSliceAnimationWidget) +{ + m_Ui->setupUi(this); + + this->connect(m_Ui->sliceRangeWidget, SIGNAL(minimumValueChanged(double)), + this, SLOT(OnFromChanged(double))); + + this->connect(m_Ui->sliceRangeWidget, SIGNAL(maximumValueChanged(double)), + this, SLOT(OnToChanged(double))); + + this->connect(m_Ui->reverseCheckBox, SIGNAL(clicked(bool)), + this, SLOT(OnReverseChanged(bool))); +} + +QmitkTimeSliceAnimationWidget::~QmitkTimeSliceAnimationWidget() +{ +} + +void QmitkTimeSliceAnimationWidget::SetAnimationItem(QmitkAnimationItem* sliceAnimationItem) +{ + m_AnimationItem = dynamic_cast(sliceAnimationItem); + + if (m_AnimationItem == NULL) + return; + + const int maximum = GetNumberOfSlices() - 1; + const int from = std::min(m_AnimationItem->GetFrom(), maximum); + const int to = std::min(m_AnimationItem->GetTo(), maximum); + + m_AnimationItem->SetFrom(from); + m_AnimationItem->SetTo(to); + + m_Ui->sliceRangeWidget->setMaximum(maximum); + m_Ui->sliceRangeWidget->setValues(from, to); + m_Ui->reverseCheckBox->setChecked(m_AnimationItem->GetReverse()); +} + +void QmitkTimeSliceAnimationWidget::OnFromChanged(double from) +{ + if (m_AnimationItem == NULL) + return; + + int intFrom = static_cast(from); + + if (m_AnimationItem->GetFrom() != intFrom) + m_AnimationItem->SetFrom(intFrom); +} + +void QmitkTimeSliceAnimationWidget::OnToChanged(double to) +{ + if (m_AnimationItem == NULL) + return; + + int intTo = static_cast(to); + + if (m_AnimationItem->GetTo() != intTo) + m_AnimationItem->SetTo(intTo); +} + +void QmitkTimeSliceAnimationWidget::OnReverseChanged(bool reverse) +{ + if (m_AnimationItem == NULL) + return; + + if (m_AnimationItem->GetReverse() != reverse) + m_AnimationItem->SetReverse(reverse); +} diff --git a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkTimeSliceAnimationWidget.h b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkTimeSliceAnimationWidget.h new file mode 100644 index 0000000000..bed8155dc0 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkTimeSliceAnimationWidget.h @@ -0,0 +1,49 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef QmitkTimeSliceAnimationWidget_h +#define QmitkTimeSliceAnimationWidget_h + +#include "QmitkAnimationWidget.h" + +class QmitkTimeSliceAnimationItem; + +namespace Ui +{ + class QmitkTimeSliceAnimationWidget; +} + +class QmitkTimeSliceAnimationWidget : public QmitkAnimationWidget +{ + Q_OBJECT + +public: + explicit QmitkTimeSliceAnimationWidget(QWidget* parent = NULL); + ~QmitkTimeSliceAnimationWidget(); + + void SetAnimationItem(QmitkAnimationItem* sliceAnimationItem); + +private slots: + void OnFromChanged(double from); + void OnToChanged(double to); + void OnReverseChanged(bool reverse); + +private: + Ui::QmitkTimeSliceAnimationWidget* m_Ui; + QmitkTimeSliceAnimationItem* m_AnimationItem; +}; + +#endif diff --git a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkTimeSliceAnimationWidget.ui b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkTimeSliceAnimationWidget.ui new file mode 100644 index 0000000000..a74fa2a150 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkTimeSliceAnimationWidget.ui @@ -0,0 +1,70 @@ + + + QmitkTimeSliceAnimationWidget + + + + 0 + 0 + 304 + 71 + + + + QmitkTimeSliceAnimationWidget + + + + + + + 0 + 0 + + + + Slice range: + + + + + + + + 0 + 0 + + + + Reverse + + + + + + + 0 + + + 999.000000000000000 + + + 999.000000000000000 + + + + + + + + ctkRangeWidget + QWidget +
ctkRangeWidget.h
+
+
+ + reverseCheckBox + + + +