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