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++

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 "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;
}