|
|
|
|
@ -82,6 +82,8 @@
|
|
|
|
|
|
|
|
|
|
// 业务逻辑相关的头文件
|
|
|
|
|
#include "nmDataAnalyzeManager.h" // 数据管理器
|
|
|
|
|
#include "nmPebiResultSnapshot.h"
|
|
|
|
|
#include "nmPebiResultSnapshotRenderAdapter.h"
|
|
|
|
|
|
|
|
|
|
// 数据过滤对话框
|
|
|
|
|
#include "nmWxPostprocessingAnimationDataFiltering.h"
|
|
|
|
|
@ -158,7 +160,8 @@ nmWxPostprocessingAnimationWidget::nmWxPostprocessingAnimationWidget(
|
|
|
|
|
QWidget(pParent),
|
|
|
|
|
m_pDataManager(pDataManager != nullptr
|
|
|
|
|
? pDataManager
|
|
|
|
|
: nmDataAnalyzeManager::getCurrentInstance())
|
|
|
|
|
: nmDataAnalyzeManager::getCurrentInstance()),
|
|
|
|
|
m_pResultRenderAdapter(new nmPebiResultSnapshotRenderAdapter())
|
|
|
|
|
{
|
|
|
|
|
// 初始化成员变量
|
|
|
|
|
m_nCurrentIndex = 0;
|
|
|
|
|
@ -174,7 +177,6 @@ nmWxPostprocessingAnimationWidget::nmWxPostprocessingAnimationWidget(
|
|
|
|
|
m_scalarBar = nullptr;
|
|
|
|
|
m_lookupTable = nullptr;
|
|
|
|
|
m_textActor = nullptr;
|
|
|
|
|
m_pCachedBaseGrid = nullptr;
|
|
|
|
|
m_thresholdFilter = nullptr;
|
|
|
|
|
|
|
|
|
|
// 初始化过滤器设置内容
|
|
|
|
|
@ -203,6 +205,11 @@ nmWxPostprocessingAnimationWidget::nmWxPostprocessingAnimationWidget(
|
|
|
|
|
connect(m_resultDialog, SIGNAL(clearContourRequested()),
|
|
|
|
|
this, SLOT(slotClearContour()));
|
|
|
|
|
|
|
|
|
|
if(!m_pDataManager.isNull()) {
|
|
|
|
|
m_pResultSnapshot =
|
|
|
|
|
m_pDataManager.data()->getPebiResultSnapshot();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 初始化时间步列表 (在 initUI 之前,因为它会影响 UI 控件的最大值)
|
|
|
|
|
this->initTimeSteps();
|
|
|
|
|
// 初始化用户界面
|
|
|
|
|
@ -212,6 +219,14 @@ nmWxPostprocessingAnimationWidget::nmWxPostprocessingAnimationWidget(
|
|
|
|
|
// 析构函数:用于在对象销毁时进行清理
|
|
|
|
|
nmWxPostprocessingAnimationWidget::~nmWxPostprocessingAnimationWidget()
|
|
|
|
|
{
|
|
|
|
|
// 先断开过滤器,再销毁适配器,确保管道不保留旧压力数组和快照引用。
|
|
|
|
|
if(m_thresholdFilter != nullptr) {
|
|
|
|
|
m_thresholdFilter->SetInputConnection(NULL);
|
|
|
|
|
}
|
|
|
|
|
delete m_pResultRenderAdapter;
|
|
|
|
|
m_pResultRenderAdapter = nullptr;
|
|
|
|
|
m_pResultSnapshot.clear();
|
|
|
|
|
|
|
|
|
|
// Qt 的父子对象机制会自动删除 QVTKWidget 和其他 Qt 控件(如 m_pSlider, m_pProgress, m_pPlayTimer)。
|
|
|
|
|
// vtkSmartPointer 会自动管理其内部 VTK 对象的内存。
|
|
|
|
|
// 但为了确保 VTK 渲染器从 RenderWindow 中被正确移除(避免潜在的 VTK 内部引用问题),
|
|
|
|
|
@ -255,8 +270,18 @@ void nmWxPostprocessingAnimationWidget::refreshResult()
|
|
|
|
|
m_pointPlacer = nullptr;
|
|
|
|
|
m_polyDataForContour = nullptr;
|
|
|
|
|
|
|
|
|
|
m_pCachedBaseGrid = pDataManager->getResultBaseGrid();
|
|
|
|
|
m_thresholdFilter->SetInputData(m_pCachedBaseGrid);
|
|
|
|
|
// 快照整体替换后先清除适配器,解除旧渲染网格持有的压力帧引用。
|
|
|
|
|
m_pResultSnapshot = pDataManager->getPebiResultSnapshot();
|
|
|
|
|
m_pResultRenderAdapter->clear();
|
|
|
|
|
if(!m_pResultSnapshot.isNull() &&
|
|
|
|
|
m_pResultRenderAdapter->initialize(
|
|
|
|
|
m_pResultSnapshot,
|
|
|
|
|
nmPebiResultSnapshotRenderAdapter::SharedPressureFrame)) {
|
|
|
|
|
m_thresholdFilter->SetInputConnection(
|
|
|
|
|
m_pResultRenderAdapter->getOutputPort());
|
|
|
|
|
} else {
|
|
|
|
|
m_thresholdFilter->SetInputConnection(NULL);
|
|
|
|
|
}
|
|
|
|
|
m_nCurrentIndex = 0;
|
|
|
|
|
m_vecTimeStepKeys.clear();
|
|
|
|
|
initTimeSteps();
|
|
|
|
|
@ -275,20 +300,22 @@ void nmWxPostprocessingAnimationWidget::refreshResult()
|
|
|
|
|
: QString("0%(0/0)"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double scalarRange[2];
|
|
|
|
|
pDataManager->getScalarRangeP(scalarRange);
|
|
|
|
|
double scalarRange[2] = { 0.0, 0.0 };
|
|
|
|
|
const bool bHasScalarRange = !m_pResultSnapshot.isNull() &&
|
|
|
|
|
m_pResultSnapshot->getScalarRange(scalarRange);
|
|
|
|
|
m_mapper->SetScalarRange(scalarRange);
|
|
|
|
|
m_lookupTable->SetRange(scalarRange);
|
|
|
|
|
m_lookupTable->Build();
|
|
|
|
|
m_thresholdFilter->ThresholdBetween(scalarRange[0], scalarRange[1]);
|
|
|
|
|
m_thresholdFilter->Modified();
|
|
|
|
|
m_bFilteringEnabled = true;
|
|
|
|
|
m_bAboveMinEnabled = true;
|
|
|
|
|
m_bFilteringEnabled = bHasScalarRange;
|
|
|
|
|
m_bAboveMinEnabled = bHasScalarRange;
|
|
|
|
|
m_dMinValue = scalarRange[0];
|
|
|
|
|
m_bBelowMaxEnabled = true;
|
|
|
|
|
m_bBelowMaxEnabled = bHasScalarRange;
|
|
|
|
|
m_dMaxValue = scalarRange[1];
|
|
|
|
|
|
|
|
|
|
if(!m_vecTimeStepKeys.isEmpty() && m_pCachedBaseGrid != nullptr) {
|
|
|
|
|
if(!m_vecTimeStepKeys.isEmpty() &&
|
|
|
|
|
m_pResultRenderAdapter->getCellCount() > 0) {
|
|
|
|
|
loadDataForIndex(0);
|
|
|
|
|
}
|
|
|
|
|
initWellDrawing();
|
|
|
|
|
@ -518,18 +545,17 @@ void nmWxPostprocessingAnimationWidget::initVTKWidget()
|
|
|
|
|
m_lookupTable->SetHueRange(0.67, 0); // 设置色调范围(从蓝色到红色)
|
|
|
|
|
m_lookupTable->Build(); // 构建颜色表
|
|
|
|
|
|
|
|
|
|
// 4. 获取基础结果网格数据
|
|
|
|
|
nmDataAnalyzeManager* pDataManager = m_pDataManager.data();
|
|
|
|
|
|
|
|
|
|
if(pDataManager) {
|
|
|
|
|
//m_pCachedBaseGrid = pDataManager->getResultBaseGridCopy();
|
|
|
|
|
m_pCachedBaseGrid = pDataManager->getResultBaseGrid();
|
|
|
|
|
}
|
|
|
|
|
// 4. 通过受控适配器建立独立渲染网格;普通 UI 不取得快照 VTK 指针。
|
|
|
|
|
const bool bResultReady = !m_pResultSnapshot.isNull() &&
|
|
|
|
|
m_pResultRenderAdapter->initialize(
|
|
|
|
|
m_pResultSnapshot,
|
|
|
|
|
nmPebiResultSnapshotRenderAdapter::SharedPressureFrame);
|
|
|
|
|
|
|
|
|
|
// 5. 创建阈值过滤器和mapper并设置输入数据
|
|
|
|
|
m_thresholdFilter = vtkSmartPointer<vtkThreshold>::New();
|
|
|
|
|
if(m_pCachedBaseGrid) {
|
|
|
|
|
m_thresholdFilter->SetInputData(m_pCachedBaseGrid);
|
|
|
|
|
if(bResultReady) {
|
|
|
|
|
m_thresholdFilter->SetInputConnection(
|
|
|
|
|
m_pResultRenderAdapter->getOutputPort());
|
|
|
|
|
}
|
|
|
|
|
m_thresholdFilter->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_CELLS, "p");
|
|
|
|
|
// 上面这行是关键!它告诉过滤器对哪个数组进行操作,
|
|
|
|
|
@ -589,8 +615,9 @@ void nmWxPostprocessingAnimationWidget::initVTKWidget()
|
|
|
|
|
|
|
|
|
|
//10. 初始渲染
|
|
|
|
|
// 设置压力标量范围
|
|
|
|
|
double scalarRange[2];
|
|
|
|
|
pDataManager->getScalarRangeP(scalarRange);
|
|
|
|
|
double scalarRange[2] = { 0.0, 0.0 };
|
|
|
|
|
const bool bHasScalarRange = bResultReady &&
|
|
|
|
|
m_pResultSnapshot->getScalarRange(scalarRange);
|
|
|
|
|
|
|
|
|
|
m_mapper->SetScalarRange(scalarRange);
|
|
|
|
|
m_lookupTable->SetRange(scalarRange);
|
|
|
|
|
@ -602,10 +629,10 @@ void nmWxPostprocessingAnimationWidget::initVTKWidget()
|
|
|
|
|
m_thresholdFilter->Modified(); // 通知过滤器其参数已修改
|
|
|
|
|
|
|
|
|
|
// 修改过滤设置
|
|
|
|
|
m_bFilteringEnabled = true;
|
|
|
|
|
m_bAboveMinEnabled = true;
|
|
|
|
|
m_bFilteringEnabled = bHasScalarRange;
|
|
|
|
|
m_bAboveMinEnabled = bHasScalarRange;
|
|
|
|
|
m_dMinValue = scalarRange[0];
|
|
|
|
|
m_bBelowMaxEnabled = true;
|
|
|
|
|
m_bBelowMaxEnabled = bHasScalarRange;
|
|
|
|
|
m_dMaxValue = scalarRange[1];
|
|
|
|
|
|
|
|
|
|
// // 创建自定义交互样式
|
|
|
|
|
@ -635,22 +662,23 @@ void nmWxPostprocessingAnimationWidget::initWellDrawing()
|
|
|
|
|
{
|
|
|
|
|
clearWellActors(); // 确保每次初始化时清空旧的 Actor,避免重复添加
|
|
|
|
|
|
|
|
|
|
nmDataAnalyzeManager* pDataManager = m_pDataManager.data();
|
|
|
|
|
|
|
|
|
|
if(!pDataManager) {
|
|
|
|
|
if(m_pResultSnapshot.isNull()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取所有井的二维位置信息,映射键为 WellCode。
|
|
|
|
|
QMap<QString, QPointF> mapWellLocations = pDataManager->getAllWellLocations();
|
|
|
|
|
|
|
|
|
|
// 遍历所有井,创建并配置它们的 3D 文本和线 Actor
|
|
|
|
|
for(auto it = mapWellLocations.constBegin(); it != mapWellLocations.constEnd(); ++it) {
|
|
|
|
|
const QString& sWellCode = it.key();
|
|
|
|
|
const QPointF& ptLocation = it.value(); // 井的二维位置 (X, Y)
|
|
|
|
|
nmDataWellBase* pWellData = pDataManager->findWellByCode(sWellCode);
|
|
|
|
|
const QString sWellName = pWellData != nullptr
|
|
|
|
|
? pWellData->getWellName() : sWellCode;
|
|
|
|
|
// 遍历快照井,实时井删除、改名或移动都不会改变历史场图标注。
|
|
|
|
|
for(int nWellIndex = 0;
|
|
|
|
|
nWellIndex < m_pResultSnapshot->getWellCount();
|
|
|
|
|
++nWellIndex) {
|
|
|
|
|
const nmPebiResultWellSnapshot* pWell =
|
|
|
|
|
m_pResultSnapshot->getWellAt(nWellIndex);
|
|
|
|
|
if(pWell == NULL) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
const QString& sWellInstanceId = pWell->m_sWellInstanceId;
|
|
|
|
|
const QPointF& ptLocation = pWell->m_oLocation;
|
|
|
|
|
const QString sWellName = pWell->m_sWellName.isEmpty()
|
|
|
|
|
? pWell->m_sWellCode : pWell->m_sWellName;
|
|
|
|
|
|
|
|
|
|
// === 1. 创建井名称的 3D 文本 Actor ===
|
|
|
|
|
// 使用 vtkBillboardTextActor3D,它始终面向相机,文字可读性最好,且是 3D 对象。
|
|
|
|
|
@ -666,7 +694,7 @@ void nmWxPostprocessingAnimationWidget::initWellDrawing()
|
|
|
|
|
textActor->SetVisibility(m_bShowWellActors ? 1 : 0);
|
|
|
|
|
|
|
|
|
|
m_renderer->AddActor(textActor); // 对于所有 3D Actor,都使用 m_renderer->AddActor()
|
|
|
|
|
m_mapWellNameActors.insert(sWellCode, textActor); // Actor内部按WellCode管理,文本仍显示井名
|
|
|
|
|
m_mapWellNameActors.insert(sWellInstanceId, textActor);
|
|
|
|
|
|
|
|
|
|
// === 2. 绘制井的线 (为每口井绘制,基于 wellLocations 的 X, Y,并延伸到 WELL_DRAWING_Z_HEIGHT) ===
|
|
|
|
|
// 创建点集合
|
|
|
|
|
@ -702,8 +730,8 @@ void nmWxPostprocessingAnimationWidget::initWellDrawing()
|
|
|
|
|
lineActor->SetVisibility(m_bShowWellActors ? 1 : 0);
|
|
|
|
|
|
|
|
|
|
m_renderer->AddActor(lineActor); // 将 3D Actor 添加到渲染器
|
|
|
|
|
// 井名允许修改或重复,井线 Actor 必须和其余求解结果一样按 WellCode 管理。
|
|
|
|
|
m_mapWellLineActors.insert(sWellCode, lineActor);
|
|
|
|
|
// Actor 同样按求解时 UUID 管理,不能被后来创建的同名或同编码井接管。
|
|
|
|
|
m_mapWellLineActors.insert(sWellInstanceId, lineActor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 强制渲染以显示新增的 Actor
|
|
|
|
|
@ -834,51 +862,37 @@ void nmWxPostprocessingAnimationWidget::initOperPannel()
|
|
|
|
|
m_pPlayTimer->setInterval(50); // 设置定时器间隔为 50 毫秒(即每 50 毫秒更新一帧)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 初始化时间步列表,从 nmDataAnalyzeManager 单例获取数据
|
|
|
|
|
// 初始化时间步列表,只读取当前窗口持有的快照
|
|
|
|
|
void nmWxPostprocessingAnimationWidget::initTimeSteps()
|
|
|
|
|
{
|
|
|
|
|
nmDataAnalyzeManager* pDataManager = m_pDataManager.data();
|
|
|
|
|
|
|
|
|
|
if(!pDataManager) {
|
|
|
|
|
m_vecTimeStepKeys.clear();
|
|
|
|
|
if(m_pResultSnapshot.isNull()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 通过公共方法获取所有时间步的键(时间戳)列表
|
|
|
|
|
QList<double> keys = pDataManager->getTimeStepKeys();
|
|
|
|
|
// 对时间步进行排序,确保动画播放顺序是正确的(从小到大)
|
|
|
|
|
std::sort(keys.begin(), keys.end());
|
|
|
|
|
m_vecTimeStepKeys = QVector<double>::fromList(keys); // 将 QList 转换为 QVector 存储
|
|
|
|
|
// Builder 已校验时间严格递增,保持快照下标与适配器帧下标一一对应。
|
|
|
|
|
m_vecTimeStepKeys.reserve(m_pResultSnapshot->getPressureFrameCount());
|
|
|
|
|
for(int nFrameIndex = 0;
|
|
|
|
|
nFrameIndex < m_pResultSnapshot->getPressureFrameCount();
|
|
|
|
|
++nFrameIndex) {
|
|
|
|
|
m_vecTimeStepKeys.append(
|
|
|
|
|
m_pResultSnapshot->getPressureTimeAt(nFrameIndex));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 根据指定索引加载并渲染一个时间步的数据
|
|
|
|
|
void nmWxPostprocessingAnimationWidget::loadDataForIndex(int index)
|
|
|
|
|
{
|
|
|
|
|
// 确保索引在有效范围内
|
|
|
|
|
if(index < 0 || index >= m_vecTimeStepKeys.size() || !m_pCachedBaseGrid) {
|
|
|
|
|
if(index < 0 || index >= m_vecTimeStepKeys.size() ||
|
|
|
|
|
m_pResultRenderAdapter == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nmDataAnalyzeManager* pDataManager = m_pDataManager.data();
|
|
|
|
|
|
|
|
|
|
if(!pDataManager) return;
|
|
|
|
|
|
|
|
|
|
// 2. 获取当前时间步对应的压力数据
|
|
|
|
|
double currentTime = m_vecTimeStepKeys[index]; // 获取当前时间步的时间戳
|
|
|
|
|
vtkSmartPointer<vtkDoubleArray> currentPressureData = pDataManager->getTimeStepData(
|
|
|
|
|
currentTime); // 获取对应的压力数据
|
|
|
|
|
|
|
|
|
|
if(!currentPressureData) return;
|
|
|
|
|
|
|
|
|
|
const char* arrayName = currentPressureData->GetName();
|
|
|
|
|
|
|
|
|
|
if (arrayName) {
|
|
|
|
|
qDebug() << "Loaded data array name is:" << arrayName;
|
|
|
|
|
} else {
|
|
|
|
|
qDebug() << "Loaded data array has no name.";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 3. 将压力数据设置到PEBI单元数据中
|
|
|
|
|
m_pCachedBaseGrid->GetCellData()->SetScalars(currentPressureData);
|
|
|
|
|
// 适配器负责共享或复制压力帧,UI 不取得可写 vtkDoubleArray 指针。
|
|
|
|
|
if(!m_pResultRenderAdapter->setPressureFrame(index)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
m_thresholdFilter->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_CELLS, "p");
|
|
|
|
|
|
|
|
|
|
// 更新时间文本演员显示的时间戳
|
|
|
|
|
@ -1160,7 +1174,8 @@ QImage nmWxPostprocessingAnimationWidget::getVTKRenderWindowAsImage()
|
|
|
|
|
void nmWxPostprocessingAnimationWidget::exportAnimationAsVideo()
|
|
|
|
|
{
|
|
|
|
|
// 检查动画数据和渲染窗口是否可用,如果不可用则弹出警告并退出。
|
|
|
|
|
if(m_vecTimeStepKeys.isEmpty() || !m_pVtkWidget || !m_pVtkWidget->GetRenderWindow()) {
|
|
|
|
|
if(m_vecTimeStepKeys.isEmpty() || m_pResultSnapshot.isNull() ||
|
|
|
|
|
!m_pVtkWidget || !m_pVtkWidget->GetRenderWindow()) {
|
|
|
|
|
QMessageBox::warning(this, tr("Warning"), tr("No animation data or render window available."));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
@ -1191,6 +1206,17 @@ void nmWxPostprocessingAnimationWidget::exportAnimationAsVideo()
|
|
|
|
|
// 停止正在进行的动画播放,避免与导出过程冲突。
|
|
|
|
|
on_stop();
|
|
|
|
|
|
|
|
|
|
// 离屏导出使用单帧复制缓冲,避免不受控导出管道持有或修改规范压力数组。
|
|
|
|
|
nmPebiResultSnapshotRenderAdapter oExportAdapter;
|
|
|
|
|
if(!oExportAdapter.initialize(
|
|
|
|
|
m_pResultSnapshot,
|
|
|
|
|
nmPebiResultSnapshotRenderAdapter::CopiedPressureFrame)) {
|
|
|
|
|
if(wasPlaying) on_start();
|
|
|
|
|
QMessageBox::warning(this, tr("Warning"),
|
|
|
|
|
tr("Cannot prepare animation result data."));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 1. 创建离屏渲染管线
|
|
|
|
|
// 创建一个VTK渲染窗口,但设置为离屏渲染,这意味着它不会在屏幕上显示。
|
|
|
|
|
vtkSmartPointer<vtkRenderWindow> offscreenRenderWindow = vtkSmartPointer<vtkRenderWindow>::New();
|
|
|
|
|
@ -1202,7 +1228,7 @@ void nmWxPostprocessingAnimationWidget::exportAnimationAsVideo()
|
|
|
|
|
// 将渲染器添加到离屏渲染窗口中。
|
|
|
|
|
offscreenRenderWindow->AddRenderer(offscreenRenderer);
|
|
|
|
|
|
|
|
|
|
// 2. 深度复制所有渲染内容 (兼容 VTK 7.1)
|
|
|
|
|
// 2. 复制轻量渲染状态;基础网格结构由适配器受控共享,不做整网格 DeepCopy。
|
|
|
|
|
|
|
|
|
|
// 复制相机:从主渲染器的相机深度复制到离屏渲染器,确保视角一致。
|
|
|
|
|
vtkSmartPointer<vtkCamera> camera = vtkSmartPointer<vtkCamera>::New();
|
|
|
|
|
@ -1217,19 +1243,12 @@ void nmWxPostprocessingAnimationWidget::exportAnimationAsVideo()
|
|
|
|
|
offscreenRenderer->SetBackground2(background2);
|
|
|
|
|
offscreenRenderer->SetGradientBackground(m_renderer->GetGradientBackground());
|
|
|
|
|
|
|
|
|
|
// 复制基础数据对象:深度复制网格数据,确保离屏渲染使用独立的数据副本。
|
|
|
|
|
vtkSmartPointer<vtkUnstructuredGrid> offscreenGrid = vtkSmartPointer<vtkUnstructuredGrid>::New();
|
|
|
|
|
|
|
|
|
|
if(m_pCachedBaseGrid) {
|
|
|
|
|
offscreenGrid->DeepCopy(m_pCachedBaseGrid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 复制主 Actor 的 Mapper、Actor 和 ScalarBar (手动复制属性)
|
|
|
|
|
// 复制 Mapper:创建一个新的Mapper,并设置其输入数据和颜色映射表等属性。
|
|
|
|
|
vtkSmartPointer<vtkDataSetMapper> offscreenMapper = vtkSmartPointer<vtkDataSetMapper>::New();
|
|
|
|
|
|
|
|
|
|
if(m_mapper) {
|
|
|
|
|
offscreenMapper->SetInputData(offscreenGrid);
|
|
|
|
|
offscreenMapper->SetInputConnection(oExportAdapter.getOutputPort());
|
|
|
|
|
offscreenMapper->SetLookupTable(m_mapper->GetLookupTable());
|
|
|
|
|
offscreenMapper->ScalarVisibilityOn();
|
|
|
|
|
offscreenMapper->SetScalarRange(m_mapper->GetScalarRange());
|
|
|
|
|
@ -1377,24 +1396,12 @@ void nmWxPostprocessingAnimationWidget::exportAnimationAsVideo()
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取数据管理器实例。
|
|
|
|
|
nmDataAnalyzeManager* pDataManager = m_pDataManager.data();
|
|
|
|
|
|
|
|
|
|
if(pDataManager) {
|
|
|
|
|
// 获取当前时间步的数据。
|
|
|
|
|
double currentTime = m_vecTimeStepKeys[i];
|
|
|
|
|
vtkSmartPointer<vtkDoubleArray> currentPressureData = pDataManager->getTimeStepData(currentTime);
|
|
|
|
|
|
|
|
|
|
if(currentPressureData) {
|
|
|
|
|
// 将数据设置到离屏网格中,并标记数据已修改。
|
|
|
|
|
vtkDataSet* dataSet = vtkDataSet::SafeDownCast(offscreenGrid);
|
|
|
|
|
|
|
|
|
|
if(dataSet) {
|
|
|
|
|
dataSet->GetCellData()->SetScalars(currentPressureData);
|
|
|
|
|
|
|
|
|
|
dataSet->Modified();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(!oExportAdapter.setPressureFrame(i)) {
|
|
|
|
|
pVideoWriter->End();
|
|
|
|
|
if(wasPlaying) on_start();
|
|
|
|
|
QMessageBox::warning(this, tr("Warning"),
|
|
|
|
|
tr("Cannot load an animation frame."));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 渲染离屏窗口。
|
|
|
|
|
|