You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nmWTAI-Platform/Src/nmNum/nmSubWxs/nmPebiGridSceneController.cpp

431 lines
14 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "nmPebiGridSceneController.h"
#include "nmPebiGridViewData.h"
#include "nmVTKBoundsGridLayer.h"
#include "nmVTKMeshLayer.h"
#include "nmVTKScalarBarLayer.h"
#include "nmVTKScene.h"
#include "nmWxVTKRenderContainerWidget.h"
#include <QCoreApplication>
#include <vtkActor.h>
#include <vtkCamera.h>
#include <vtkMath.h>
#include <vtkProperty.h>
#include <vtkRenderer.h>
#include <vtkUnstructuredGrid.h>
namespace {
QString controllerText(const char* pText)
{
return QCoreApplication::translate(
"nmPebiGridSceneController", pText);
}
bool getFiniteGridBounds(vtkUnstructuredGrid* pGrid, double dBounds[6])
{
if(pGrid == NULL || dBounds == NULL) {
return false;
}
pGrid->GetBounds(dBounds);
if(!vtkMath::AreBoundsInitialized(dBounds)) {
return false;
}
for(int nIndex = 0; nIndex < 6; ++nIndex) {
if(!vtkMath::IsFinite(dBounds[nIndex])) {
return false;
}
}
return dBounds[0] <= dBounds[1] &&
dBounds[2] <= dBounds[3] &&
dBounds[4] <= dBounds[5];
}
}
class nmPebiGridSceneControllerPrivate
{
public:
explicit nmPebiGridSceneControllerPrivate(
nmWxVTKRenderContainerWidget* pRenderContainer)
: m_pContainer(pRenderContainer),
m_pMeshLayer(NULL),
m_pScalarBarLayer(NULL),
m_pBoundsGridLayer(NULL),
m_bGridLinesVisible(true),
m_bScalarBarVisible(true),
m_bBoundsGridVisible(false),
m_bPropertySelectionExplicit(false),
m_bHasData(false)
{
}
bool ensureBaseLayers()
{
nmVTKScene* pScene = m_pContainer != NULL
? m_pContainer->getScene() : NULL;
vtkRenderer* pRenderer = m_pContainer != NULL
? m_pContainer->getRenderer() : NULL;
if(pScene == NULL || pRenderer == NULL) {
return false;
}
if(m_pMeshLayer == NULL) {
nmVTKMeshLayer* pLayer =
new nmVTKMeshLayer("pebi.grid.mesh");
pLayer->setVisible(false);
if(!pScene->addLayer(pLayer)) {
delete pLayer;
return false;
}
m_pMeshLayer = pLayer;
// 固定面色、边线颜色和完全不透明外观沿用旧 PEBI 预览。
m_pMeshLayer->getActor()->GetProperty()->SetColor(
0.0, 120.0 / 255.0, 215.0 / 255.0);
m_pMeshLayer->getActor()->GetProperty()->SetEdgeColor(
0.0, 0.0, 0.0);
}
if(m_pBoundsGridLayer == NULL) {
nmVTKBoundsGridLayer* pLayer =
new nmVTKBoundsGridLayer("pebi.grid.bounds_grid");
pLayer->setMode(nmVTKBoundsGridLayer::Mode_PlanarXY);
pLayer->setCamera(pRenderer->GetActiveCamera());
pLayer->setVisible(false);
if(!pScene->addLayer(pLayer)) {
delete pLayer;
return false;
}
m_pBoundsGridLayer = pLayer;
}
return true;
}
bool ensureScalarBarLayer()
{
if(m_pScalarBarLayer != NULL) {
return true;
}
nmVTKScene* pScene = m_pContainer != NULL
? m_pContainer->getScene() : NULL;
if(pScene == NULL || m_pMeshLayer == NULL) {
return false;
}
// 色标只在第一次选择有效标量时创建,并共享 MeshLayer 的 LUT。
nmVTKScalarBarLayer* pLayer =
new nmVTKScalarBarLayer("pebi.grid.scalar_bar");
pLayer->setLookupTable(m_pMeshLayer->getLookupTable());
pLayer->setPosition(0.86, 0.12);
pLayer->setSize(0.10, 0.76);
pLayer->setVisible(false);
if(!pScene->addLayer(pLayer)) {
delete pLayer;
return false;
}
m_pScalarBarLayer = pLayer;
return true;
}
bool applyProperty(const QString& sPropertyName)
{
if(m_pMeshLayer == NULL) {
return false;
}
if(sPropertyName.isEmpty()) {
m_sPropertyName.clear();
m_pMeshLayer->setScalarVisibility(false);
if(m_pScalarBarLayer != NULL) {
m_pScalarBarLayer->setVisible(false);
}
return true;
}
if(sPropertyName != "Material" || !m_oViewData.hasMaterial() ||
!m_pMeshLayer->setScalarArray(
sPropertyName, nmVTKMeshLayer::ScalarAssociation_CellData)) {
// 无效属性不能沿用上一网格的标量着色或色标范围。
m_sPropertyName.clear();
m_pMeshLayer->setScalarVisibility(false);
if(m_pScalarBarLayer != NULL) {
m_pScalarBarLayer->setVisible(false);
}
return false;
}
if(!ensureScalarBarLayer()) {
m_sPropertyName.clear();
m_pMeshLayer->setScalarVisibility(false);
return false;
}
m_sPropertyName = sPropertyName;
m_pMeshLayer->setScalarVisibility(true);
m_pScalarBarLayer->setLookupTable(
m_pMeshLayer->getLookupTable());
m_pScalarBarLayer->setTitle(sPropertyName);
m_pScalarBarLayer->setVisible(m_bScalarBarVisible);
return true;
}
bool bindViewData(const nmPebiGridViewData& oViewData,
const QString& sRequestedProperty,
const double dBounds[6])
{
if(m_pMeshLayer == NULL || m_pBoundsGridLayer == NULL ||
dBounds == NULL) {
return false;
}
// 本函数只提交已在外层验证过的数据,不渲染也不改变相机。
m_oViewData = oViewData;
if(!m_pMeshLayer->setDataSet(oViewData.getGrid())) {
m_oViewData.clear();
return false;
}
m_pMeshLayer->setEdgeVisibility(m_bGridLinesVisible);
m_pMeshLayer->setVisible(true);
if(!m_pBoundsGridLayer->setBounds(
dBounds[0], dBounds[1], dBounds[2],
dBounds[3], dBounds[4], dBounds[5])) {
m_pMeshLayer->setDataSet(NULL);
m_pMeshLayer->setVisible(false);
m_oViewData.clear();
return false;
}
m_pBoundsGridLayer->setVisible(m_bBoundsGridVisible);
m_bHasData = true;
// 属性不可用只回退固定面色,不影响已经验证成功的网格几何提交。
applyProperty(sRequestedProperty);
return true;
}
void releaseGridData()
{
// 先断开 Mapper 对旧网格的引用,再释放 ViewData 的共享引用。
if(m_pMeshLayer != NULL) {
m_pMeshLayer->setScalarVisibility(false);
m_pMeshLayer->setDataSet(NULL);
m_pMeshLayer->setVisible(false);
}
if(m_pScalarBarLayer != NULL) {
m_pScalarBarLayer->setVisible(false);
}
if(m_pBoundsGridLayer != NULL) {
m_pBoundsGridLayer->setVisible(false);
}
m_oViewData.clear();
m_sPropertyName.clear();
m_bHasData = false;
}
nmWxVTKRenderContainerWidget* m_pContainer; ///< 非所有权指针。
nmVTKMeshLayer* m_pMeshLayer; ///< Scene 所有,控制器只观察。
nmVTKScalarBarLayer* m_pScalarBarLayer; ///< Scene 所有,按需创建。
nmVTKBoundsGridLayer* m_pBoundsGridLayer; ///< Scene 所有。
nmPebiGridViewData m_oViewData;
bool m_bGridLinesVisible;
bool m_bScalarBarVisible; ///< 用户偏好,无属性时仍保留。
bool m_bBoundsGridVisible;
bool m_bPropertySelectionExplicit; ///< 是否已由业务界面明确选择属性。
bool m_bHasData;
QString m_sRequestedPropertyName; ///< 显式选择偏好,可暂时不可用。
QString m_sPropertyName;
};
nmPebiGridSceneController::nmPebiGridSceneController(
nmWxVTKRenderContainerWidget* pContainer)
: m_pPrivate(new nmPebiGridSceneControllerPrivate(pContainer))
{
}
nmPebiGridSceneController::~nmPebiGridSceneController()
{
if(m_pPrivate != NULL) {
// Layer 已归 Scene 所有;这里只解除数据和非所有权指针。
m_pPrivate->releaseGridData();
m_pPrivate->m_pContainer = NULL;
m_pPrivate->m_pMeshLayer = NULL;
m_pPrivate->m_pScalarBarLayer = NULL;
m_pPrivate->m_pBoundsGridLayer = NULL;
delete m_pPrivate;
m_pPrivate = NULL;
}
}
bool nmPebiGridSceneController::setViewData(
const nmPebiGridViewData& oViewData,
QString* pError)
{
if(pError != NULL) {
pError->clear();
}
if(m_pPrivate == NULL || m_pPrivate->m_pContainer == NULL ||
!oViewData.isValid()) {
if(pError != NULL) {
*pError = controllerText("The grid preview data is invalid.");
}
return false;
}
double dBounds[6];
if(!getFiniteGridBounds(oViewData.getGrid(), dBounds)) {
if(pError != NULL) {
*pError = controllerText("The grid bounds are invalid.");
}
return false;
}
if(!m_pPrivate->ensureBaseLayers()) {
if(pError != NULL) {
*pError = controllerText("Unable to create the grid render layers.");
}
return false;
}
QString sRequestedProperty;
if(m_pPrivate->m_bPropertySelectionExplicit) {
// 用户明确选择优先;即使属性暂时缺失,也保留偏好供后续网格恢复。
sRequestedProperty = m_pPrivate->m_sRequestedPropertyName;
} else if(oViewData.hasMaterial()) {
// 默认选择与“是否首次装入网格”无关,首次出现 Material 时同样生效。
sRequestedProperty = "Material";
}
// 强引用保留上一份成功数据,提交任一步失败时可以完整恢复旧画面。
const bool bHadPreviousData = m_pPrivate->m_bHasData;
const nmPebiGridViewData oPreviousViewData = m_pPrivate->m_oViewData;
const QString sPreviousProperty = m_pPrivate->m_sPropertyName;
double dPreviousBounds[6];
const bool bHasPreviousBounds = bHadPreviousData &&
getFiniteGridBounds(oPreviousViewData.getGrid(), dPreviousBounds);
// 几何替换先解除旧输入再共享新网格Renderer 和图层对象保持不变。
m_pPrivate->releaseGridData();
if(!m_pPrivate->bindViewData(oViewData, sRequestedProperty, dBounds)) {
// 回滚同样不渲染;外层失败状态会决定恢复旧画面还是显示错误页。
m_pPrivate->releaseGridData();
if(bHadPreviousData && bHasPreviousBounds) {
m_pPrivate->bindViewData(
oPreviousViewData,
sPreviousProperty,
dPreviousBounds);
}
if(pError != NULL) {
*pError = controllerText("Unable to bind the grid render data.");
}
return false;
}
// 几何变化始终恢复正交顶视图并适配;整批更新最终只在就绪入口渲染一次。
m_pPrivate->m_pContainer->fitTopViewWithoutRender();
m_pPrivate->m_pContainer->showReadyState();
return true;
}
void nmPebiGridSceneController::clear()
{
if(m_pPrivate == NULL) {
return;
}
m_pPrivate->releaseGridData();
m_pPrivate->m_sPropertyName.clear();
m_pPrivate->m_sRequestedPropertyName.clear();
m_pPrivate->m_bGridLinesVisible = true;
m_pPrivate->m_bScalarBarVisible = true;
m_pPrivate->m_bBoundsGridVisible = false;
m_pPrivate->m_bPropertySelectionExplicit = false;
}
void nmPebiGridSceneController::setGridLinesVisible(bool bVisible)
{
if(m_pPrivate == NULL) {
return;
}
m_pPrivate->m_bGridLinesVisible = bVisible;
if(m_pPrivate->m_pMeshLayer != NULL) {
m_pPrivate->m_pMeshLayer->setEdgeVisibility(bVisible);
}
if(m_pPrivate->m_bHasData && m_pPrivate->m_pContainer != NULL) {
m_pPrivate->m_pContainer->renderView();
}
}
bool nmPebiGridSceneController::setProperty(const QString& sPropertyName)
{
if(m_pPrivate == NULL || !m_pPrivate->m_bHasData) {
return false;
}
const bool bSucceeded = m_pPrivate->applyProperty(sPropertyName);
// 只有公开入口代表用户/业务明确选择,内部默认绑定不会污染该状态。
m_pPrivate->m_bPropertySelectionExplicit = true;
m_pPrivate->m_sRequestedPropertyName = bSucceeded
? sPropertyName : QString();
if(m_pPrivate->m_pContainer != NULL) {
m_pPrivate->m_pContainer->renderView();
}
return bSucceeded;
}
void nmPebiGridSceneController::setScalarBarVisible(bool bVisible)
{
if(m_pPrivate == NULL) {
return;
}
// 无属性时只保存偏好;重新选择 Material 后按该偏好恢复色标。
m_pPrivate->m_bScalarBarVisible = bVisible;
if(m_pPrivate->m_pScalarBarLayer != NULL) {
m_pPrivate->m_pScalarBarLayer->setVisible(
bVisible && m_pPrivate->m_bHasData &&
!m_pPrivate->m_sPropertyName.isEmpty());
}
if(m_pPrivate->m_bHasData && m_pPrivate->m_pContainer != NULL) {
m_pPrivate->m_pContainer->renderView();
}
}
void nmPebiGridSceneController::setBoundsGridVisible(bool bVisible)
{
if(m_pPrivate == NULL) {
return;
}
m_pPrivate->m_bBoundsGridVisible = bVisible;
if(m_pPrivate->m_pBoundsGridLayer != NULL) {
m_pPrivate->m_pBoundsGridLayer->setVisible(
bVisible && m_pPrivate->m_bHasData);
}
if(m_pPrivate->m_bHasData && m_pPrivate->m_pContainer != NULL) {
m_pPrivate->m_pContainer->renderView();
}
}
bool nmPebiGridSceneController::hasViewData() const
{
return m_pPrivate != NULL && m_pPrivate->m_bHasData;
}
QString nmPebiGridSceneController::getProperty() const
{
return m_pPrivate != NULL
? m_pPrivate->m_sPropertyName : QString();
}
bool nmPebiGridSceneController::isGridLinesVisible() const
{
return m_pPrivate != NULL && m_pPrivate->m_bGridLinesVisible;
}
bool nmPebiGridSceneController::isScalarBarVisible() const
{
return m_pPrivate != NULL && m_pPrivate->m_bScalarBarVisible;
}
bool nmPebiGridSceneController::isBoundsGridVisible() const
{
return m_pPrivate != NULL && m_pPrivate->m_bBoundsGridVisible;
}