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

280 lines
9.1 KiB
C++

#include "nmPebiGridSceneController.h"
#include "nmPebiGridViewData.h"
#include "nmVTKMeshLayer.h"
#include "nmVTKPlanarScaleGridLayer.h"
#include "nmVTKScene.h"
#include "nmWxVTKRenderContainerWidget.h"
#include <QCoreApplication>
#include <vtkActor.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 == nullptr || dBounds == nullptr) {
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(nullptr),
m_pPlanarScaleGridLayer(nullptr),
m_bBoundsGridVisible(false),
m_bHasData(false)
{
}
bool ensureBaseLayers()
{
nmVTKScene* pScene = m_pContainer != nullptr
? m_pContainer->getScene() : nullptr;
vtkRenderer* pRenderer = m_pContainer != nullptr
? m_pContainer->getRenderer() : nullptr;
if(pScene == nullptr || pRenderer == nullptr) {
return false;
}
if(m_pMeshLayer == nullptr) {
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(
211.0 / 255.0, 211.0 / 255.0,
211.0 / 255.0);
m_pMeshLayer->getActor()->GetProperty()->SetEdgeColor(
0.0, 0.0, 0.0);
// 仅关闭当前 PEBI 预览 Actor 的光照,避免固定面色随视角变化。
m_pMeshLayer->getActor()->GetProperty()->LightingOff();
}
if(m_pPlanarScaleGridLayer == nullptr) {
nmVTKPlanarScaleGridLayer* pLayer =
new nmVTKPlanarScaleGridLayer("pebi.grid.scale_grid");
pLayer->setVisible(false);
if(!pScene->addLayer(pLayer)) {
delete pLayer;
return false;
}
m_pPlanarScaleGridLayer = pLayer;
}
return true;
}
bool bindViewData(const nmPebiGridViewData& oViewData,
const double dBounds[6])
{
if(m_pMeshLayer == nullptr || m_pPlanarScaleGridLayer == nullptr ||
dBounds == nullptr) {
return false;
}
// 本函数只提交已在外层验证过的数据,不渲染也不改变相机。
m_oViewData = oViewData;
if(!m_pMeshLayer->setDataSet(oViewData.getGrid())) {
m_oViewData.clear();
return false;
}
// 输入可能包含历史数组,网格预览始终关闭标量着色并显示单元边线。
m_pMeshLayer->setScalarVisibility(false);
m_pMeshLayer->setDisplayMode(
nmVTKMeshLayer::DisplayMode_SurfaceWithEdges);
m_pMeshLayer->setVisible(true);
if(!m_pPlanarScaleGridLayer->setBounds(
dBounds[0], dBounds[1], dBounds[2],
dBounds[3], dBounds[4])) {
m_pMeshLayer->setDataSet(nullptr);
m_pMeshLayer->setVisible(false);
m_oViewData.clear();
return false;
}
m_pPlanarScaleGridLayer->setVisible(m_bBoundsGridVisible);
m_bHasData = true;
// 只有整份网格绑定成功后才允许公共拾取器命中主 Mesh Actor。
if(m_pContainer != nullptr) {
m_pContainer->setRotationCenterPickTarget(
m_pMeshLayer->getActor());
}
return true;
}
void releaseGridData()
{
// 先取消临时拾取并清除弱目标,再解除 Mapper 对网格的共享引用。
if(m_pContainer != nullptr) {
m_pContainer->setRotationCenterPickTarget(nullptr);
}
// 先断开 Mapper 对旧网格的引用,再释放 ViewData 的共享引用。
if(m_pMeshLayer != nullptr) {
m_pMeshLayer->setScalarVisibility(false);
m_pMeshLayer->setDataSet(nullptr);
m_pMeshLayer->setVisible(false);
}
if(m_pPlanarScaleGridLayer != nullptr) {
m_pPlanarScaleGridLayer->setVisible(false);
}
m_oViewData.clear();
m_bHasData = false;
}
nmWxVTKRenderContainerWidget* m_pContainer; ///< 非所有权指针。
nmVTKMeshLayer* m_pMeshLayer; ///< Scene 所有,控制器只观察。
nmVTKPlanarScaleGridLayer* m_pPlanarScaleGridLayer; ///< Scene 所有。
nmPebiGridViewData m_oViewData;
bool m_bBoundsGridVisible;
bool m_bHasData;
};
nmPebiGridSceneController::nmPebiGridSceneController(
nmWxVTKRenderContainerWidget* pContainer)
: m_pPrivate(new nmPebiGridSceneControllerPrivate(pContainer))
{
}
nmPebiGridSceneController::~nmPebiGridSceneController()
{
if(m_pPrivate != nullptr) {
// Layer 已归 Scene 所有;这里只解除数据和非所有权指针。
m_pPrivate->releaseGridData();
m_pPrivate->m_pContainer = nullptr;
m_pPrivate->m_pMeshLayer = nullptr;
m_pPrivate->m_pPlanarScaleGridLayer = nullptr;
delete m_pPrivate;
m_pPrivate = nullptr;
}
}
bool nmPebiGridSceneController::setViewData(
const nmPebiGridViewData& oViewData,
QString* pError)
{
if(pError != nullptr) {
pError->clear();
}
if(m_pPrivate == nullptr || m_pPrivate->m_pContainer == nullptr ||
!oViewData.isValid()) {
if(pError != nullptr) {
*pError = controllerText("The grid preview data is invalid.");
}
return false;
}
double dBounds[6];
if(!getFiniteGridBounds(oViewData.getGrid(), dBounds)) {
if(pError != nullptr) {
*pError = controllerText("The grid bounds are invalid.");
}
return false;
}
if(!m_pPrivate->ensureBaseLayers()) {
if(pError != nullptr) {
*pError = controllerText("Unable to create the grid render layers.");
}
return false;
}
// 强引用保留上一份成功数据,提交任一步失败时可以完整恢复旧画面。
const bool bHadPreviousData = m_pPrivate->m_bHasData;
const nmPebiGridViewData oPreviousViewData = m_pPrivate->m_oViewData;
double dPreviousBounds[6];
const bool bHasPreviousBounds = bHadPreviousData &&
getFiniteGridBounds(oPreviousViewData.getGrid(), dPreviousBounds);
// 几何替换先解除旧输入再共享新网格Renderer 和图层对象保持不变。
m_pPrivate->releaseGridData();
if(!m_pPrivate->bindViewData(oViewData, dBounds)) {
// 回滚同样不渲染;外层失败状态会决定恢复旧画面还是显示错误页。
m_pPrivate->releaseGridData();
if(bHadPreviousData && bHasPreviousBounds) {
m_pPrivate->bindViewData(
oPreviousViewData,
dPreviousBounds);
}
if(pError != nullptr) {
*pError = controllerText("Unable to bind the grid render data.");
}
return false;
}
// 几何变化恢复正交顶视图,并将独立枢轴初始化为新网格可见边界中心。
// 两步都不立即渲染,整批更新最终只在就绪入口提交一次。
m_pPrivate->m_pContainer->fitTopViewWithoutRender();
m_pPrivate->m_pContainer->resetRotationCenterWithoutRender();
m_pPrivate->m_pContainer->showReadyState();
return true;
}
void nmPebiGridSceneController::clear()
{
if(m_pPrivate == nullptr) {
return;
}
m_pPrivate->releaseGridData();
m_pPrivate->m_bBoundsGridVisible = false;
}
void nmPebiGridSceneController::setBoundsGridVisible(bool bVisible)
{
if(m_pPrivate == nullptr) {
return;
}
m_pPrivate->m_bBoundsGridVisible = bVisible;
if(m_pPrivate->m_pPlanarScaleGridLayer != nullptr) {
m_pPrivate->m_pPlanarScaleGridLayer->setVisible(
bVisible && m_pPrivate->m_bHasData);
}
if(m_pPrivate->m_bHasData && m_pPrivate->m_pContainer != nullptr) {
m_pPrivate->m_pContainer->renderView();
}
}
bool nmPebiGridSceneController::hasViewData() const
{
return m_pPrivate != nullptr && m_pPrivate->m_bHasData;
}
bool nmPebiGridSceneController::isBoundsGridVisible() const
{
return m_pPrivate != nullptr && m_pPrivate->m_bBoundsGridVisible;
}