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/nmRender/nmVTKMeshLayer.cpp

309 lines
9.0 KiB
C++

#include "nmVTKMeshLayer.h"
#include <QCoreApplication>
#include <QThread>
#include <QtGlobal>
#include <vtkActor.h>
#include <vtkCellData.h>
#include <vtkDataArray.h>
#include <vtkDataSet.h>
#include <vtkDataSetMapper.h>
#include <vtkLookupTable.h>
#include <vtkMath.h>
#include <vtkPointData.h>
#include <vtkProperty.h>
namespace {
// Mapper、Actor 和输入数据都属于 VTK 状态,只允许 GUI 线程修改。
bool isMeshLayerGuiThread()
{
QCoreApplication* pApplication = QCoreApplication::instance();
return pApplication == NULL ||
pApplication->thread() == QThread::currentThread();
}
}
nmVTKMeshLayer::nmVTKMeshLayer(const QString& sLayerId)
: nmVTKRenderLayer(sLayerId),
m_pDataSet(NULL),
m_pMapper(vtkSmartPointer<vtkDataSetMapper>::New()),
m_pActor(vtkSmartPointer<vtkActor>::New()),
m_pLookupTable(vtkSmartPointer<vtkLookupTable>::New()),
m_eDisplayMode(DisplayMode_Surface),
m_eScalarAssociation(ScalarAssociation_CellData),
m_bUsingExplicitScalarRange(false)
{
Q_ASSERT(isMeshLayerGuiThread());
// 图层独占 Mapper、Actor 和 LookupTable数据集通过智能指针共享。
m_pLookupTable->SetNumberOfTableValues(256);
m_pLookupTable->SetHueRange(0.67, 0.0);
m_pLookupTable->Build();
m_pMapper->SetLookupTable(m_pLookupTable);
m_pMapper->ScalarVisibilityOff();
m_pActor->SetMapper(m_pMapper);
m_pActor->GetProperty()->SetRepresentationToSurface();
m_pActor->GetProperty()->EdgeVisibilityOff();
setRenderProp(m_pActor);
}
nmVTKMeshLayer::~nmVTKMeshLayer()
{
Q_ASSERT(isMeshLayerGuiThread());
// 派生成员释放前先解除 Renderer基类析构中的 detach 仍保持幂等。
detach();
m_pDataSet = NULL;
}
bool nmVTKMeshLayer::setDataSet(vtkDataSet* pDataSet)
{
Q_ASSERT(isMeshLayerGuiThread());
if(!isMeshLayerGuiThread()) {
return false;
}
// vtkSmartPointer 仅增加引用计数,不复制点、单元或属性数组。
m_pDataSet = pDataSet;
m_pMapper->SetInputData(pDataSet);
if(pDataSet == NULL) {
clearInvalidScalarState();
return false;
}
// 更换数据集时保留调用方此前的数组选择;若同名数组存在则恢复其映射方式。
if(!m_aScalarArrayName.isEmpty()) {
if(getSelectedScalarArray() == NULL) {
clearInvalidScalarState();
return false;
}
if(m_eScalarAssociation == ScalarAssociation_CellData) {
m_pMapper->SetScalarModeToUseCellFieldData();
} else {
m_pMapper->SetScalarModeToUsePointFieldData();
}
m_pMapper->SelectColorArray(m_aScalarArrayName.constData());
if(!m_bUsingExplicitScalarRange) {
if(!applyDataScalarRange()) {
clearInvalidScalarState();
return false;
}
}
}
return true;
}
vtkDataSet* nmVTKMeshLayer::getDataSet() const
{
return m_pDataSet;
}
void nmVTKMeshLayer::setDisplayMode(DisplayMode eMode)
{
Q_ASSERT(isMeshLayerGuiThread());
if(!isMeshLayerGuiThread() || m_pActor == NULL) {
return;
}
// 未识别枚举值按纯表面处理,避免把无效值带入 VTK Property。
m_eDisplayMode = eMode == DisplayMode_SurfaceWithEdges
? DisplayMode_SurfaceWithEdges : DisplayMode_Surface;
vtkProperty* pProperty = m_pActor->GetProperty();
pProperty->SetRepresentationToSurface();
pProperty->SetEdgeVisibility(
m_eDisplayMode == DisplayMode_SurfaceWithEdges ? 1 : 0);
}
nmVTKMeshLayer::DisplayMode nmVTKMeshLayer::getDisplayMode() const
{
return m_eDisplayMode;
}
bool nmVTKMeshLayer::setOpacity(double dOpacity)
{
Q_ASSERT(isMeshLayerGuiThread());
if(!isMeshLayerGuiThread() || !vtkMath::IsFinite(dOpacity) ||
m_pActor == NULL) {
return false;
}
m_pActor->GetProperty()->SetOpacity(qBound(0.0, dOpacity, 1.0));
return true;
}
double nmVTKMeshLayer::getOpacity() const
{
return m_pActor != NULL ? m_pActor->GetProperty()->GetOpacity() : 0.0;
}
void nmVTKMeshLayer::setScalarVisibility(bool bVisible)
{
Q_ASSERT(isMeshLayerGuiThread());
if(!isMeshLayerGuiThread() || m_pMapper == NULL) {
return;
}
m_pMapper->SetScalarVisibility(bVisible ? 1 : 0);
}
bool nmVTKMeshLayer::isScalarVisible() const
{
return m_pMapper != NULL && m_pMapper->GetScalarVisibility() != 0;
}
bool nmVTKMeshLayer::setScalarArray(
const QString& sArrayName,
ScalarAssociation eAssociation)
{
Q_ASSERT(isMeshLayerGuiThread());
if(!isMeshLayerGuiThread() || sArrayName.isEmpty() ||
m_pDataSet == NULL || m_pMapper == NULL ||
(eAssociation != ScalarAssociation_CellData &&
eAssociation != ScalarAssociation_PointData)) {
return false;
}
const QByteArray aArrayName = sArrayName.toUtf8();
vtkDataArray* pArray = eAssociation == ScalarAssociation_CellData
? m_pDataSet->GetCellData()->GetArray(aArrayName.constData())
: m_pDataSet->GetPointData()->GetArray(aArrayName.constData());
if(pArray == NULL) {
// 失败时保留原数组选择和原 Mapper 状态。
return false;
}
double dRange[2] = { 0.0, 0.0 };
if(!m_bUsingExplicitScalarRange) {
pArray->GetRange(dRange);
if(!vtkMath::IsFinite(dRange[0]) ||
!vtkMath::IsFinite(dRange[1]) || dRange[0] > dRange[1]) {
// 自动范围无效时不提交新数组选择,避免形成半更新状态。
return false;
}
}
m_aScalarArrayName = aArrayName;
m_eScalarAssociation = eAssociation;
if(eAssociation == ScalarAssociation_CellData) {
m_pMapper->SetScalarModeToUseCellFieldData();
} else {
m_pMapper->SetScalarModeToUsePointFieldData();
}
m_pMapper->SelectColorArray(m_aScalarArrayName.constData());
// 已设置显式范围时不覆盖,否则同步提交已经验证的数据范围。
if(!m_bUsingExplicitScalarRange) {
m_pMapper->SetScalarRange(dRange);
m_pLookupTable->SetRange(dRange);
m_pLookupTable->Build();
}
return true;
}
QString nmVTKMeshLayer::getScalarArrayName() const
{
return QString::fromUtf8(m_aScalarArrayName.constData());
}
nmVTKMeshLayer::ScalarAssociation
nmVTKMeshLayer::getScalarAssociation() const
{
return m_eScalarAssociation;
}
bool nmVTKMeshLayer::setScalarRange(double dMinimum, double dMaximum)
{
Q_ASSERT(isMeshLayerGuiThread());
if(!isMeshLayerGuiThread() || !vtkMath::IsFinite(dMinimum) ||
!vtkMath::IsFinite(dMaximum) || dMinimum > dMaximum ||
m_pMapper == NULL || m_pLookupTable == NULL) {
return false;
}
// Mapper 与 LookupTable 使用同一范围,保证几何着色和外接色标一致。
m_pMapper->SetScalarRange(dMinimum, dMaximum);
m_pLookupTable->SetRange(dMinimum, dMaximum);
m_pLookupTable->Build();
m_bUsingExplicitScalarRange = true;
return true;
}
bool nmVTKMeshLayer::restoreDataScalarRange()
{
Q_ASSERT(isMeshLayerGuiThread());
if(!isMeshLayerGuiThread() || !applyDataScalarRange()) {
return false;
}
// 只有成功应用数据范围后才退出显式范围模式。
m_bUsingExplicitScalarRange = false;
return true;
}
bool nmVTKMeshLayer::isUsingExplicitScalarRange() const
{
return m_bUsingExplicitScalarRange;
}
vtkDataSetMapper* nmVTKMeshLayer::getMapper() const
{
return m_pMapper;
}
vtkActor* nmVTKMeshLayer::getActor() const
{
return m_pActor;
}
vtkLookupTable* nmVTKMeshLayer::getLookupTable() const
{
return m_pLookupTable;
}
vtkDataArray* nmVTKMeshLayer::getSelectedScalarArray() const
{
if(m_pDataSet == NULL || m_aScalarArrayName.isEmpty()) {
return NULL;
}
return m_eScalarAssociation == ScalarAssociation_CellData
? m_pDataSet->GetCellData()->GetArray(
m_aScalarArrayName.constData())
: m_pDataSet->GetPointData()->GetArray(
m_aScalarArrayName.constData());
}
bool nmVTKMeshLayer::applyDataScalarRange()
{
vtkDataArray* pArray = getSelectedScalarArray();
if(pArray == NULL || m_pMapper == NULL || m_pLookupTable == NULL) {
return false;
}
// GetRange 只扫描当前选中的数组;无效或非有限范围不会污染现有颜色表。
double dRange[2] = { 0.0, 0.0 };
pArray->GetRange(dRange);
if(!vtkMath::IsFinite(dRange[0]) || !vtkMath::IsFinite(dRange[1]) ||
dRange[0] > dRange[1]) {
return false;
}
m_pMapper->SetScalarRange(dRange);
m_pLookupTable->SetRange(dRange);
m_pLookupTable->Build();
return true;
}
void nmVTKMeshLayer::clearInvalidScalarState()
{
// 失效选择不能继续驱动几何着色,也不能让外接色标沿用上一数据集范围。
m_aScalarArrayName.clear();
m_eScalarAssociation = ScalarAssociation_CellData;
m_bUsingExplicitScalarRange = false;
m_pMapper->ScalarVisibilityOff();
m_pMapper->SetScalarModeToDefault();
m_pMapper->SetScalarRange(0.0, 1.0);
m_pLookupTable->SetRange(0.0, 1.0);
m_pLookupTable->Build();
}