|
|
#include "nmVTKScene.h"
|
|
|
|
|
|
#include "nmVTKRenderLayer.h"
|
|
|
|
|
|
#include <QCoreApplication>
|
|
|
#include <QThread>
|
|
|
|
|
|
#include <vtkRenderer.h>
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
// Release 构建也会通过返回值拒绝跨线程操作,断言用于尽早暴露调用错误。
|
|
|
bool isSceneGuiThread()
|
|
|
{
|
|
|
QCoreApplication* pApplication = QCoreApplication::instance();
|
|
|
return pApplication == nullptr ||
|
|
|
pApplication->thread() == QThread::currentThread();
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
nmVTKScene::nmVTKScene(vtkRenderer* pRenderer)
|
|
|
: m_pRenderer(pRenderer)
|
|
|
{
|
|
|
Q_ASSERT(isSceneGuiThread());
|
|
|
// Scene 不增加 Renderer 引用计数,生命周期由外层容器统一编排。
|
|
|
}
|
|
|
|
|
|
nmVTKScene::~nmVTKScene()
|
|
|
{
|
|
|
Q_ASSERT(isSceneGuiThread());
|
|
|
// 即使在 Release 中违反线程约束,也优先解除 Renderer 对 Prop 的引用。
|
|
|
clearLayers();
|
|
|
m_pRenderer = nullptr;
|
|
|
}
|
|
|
|
|
|
bool nmVTKScene::addLayer(nmVTKRenderLayer* pLayer)
|
|
|
{
|
|
|
Q_ASSERT(isSceneGuiThread());
|
|
|
if(!isSceneGuiThread() || pLayer == nullptr || m_pRenderer == nullptr) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
const QString sLayerId = pLayer->getLayerId();
|
|
|
if(sLayerId.isEmpty() || m_mapLayers.contains(sLayerId)) {
|
|
|
// 加入失败时绝不删除图层,所有权仍由调用方负责。
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
// 先认领所有权再挂载,阻止同一裸指针同时进入两个 Scene 的所有权容器。
|
|
|
if(!pLayer->claimSceneOwnership(this)) {
|
|
|
return false;
|
|
|
}
|
|
|
if(!pLayer->attach(m_pRenderer)) {
|
|
|
// attach 失败不会留下 Renderer 引用,也不会改变图层所有权。
|
|
|
pLayer->releaseSceneOwnership(this);
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
// 只有挂载成功后才写入所有权容器。
|
|
|
m_mapLayers.insert(sLayerId, pLayer);
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
nmVTKRenderLayer* nmVTKScene::getLayer(const QString& sLayerId) const
|
|
|
{
|
|
|
Q_ASSERT(isSceneGuiThread());
|
|
|
if(!isSceneGuiThread()) {
|
|
|
return nullptr;
|
|
|
}
|
|
|
return m_mapLayers.value(sLayerId, nullptr);
|
|
|
}
|
|
|
|
|
|
bool nmVTKScene::removeLayer(const QString& sLayerId)
|
|
|
{
|
|
|
Q_ASSERT(isSceneGuiThread());
|
|
|
if(!isSceneGuiThread() || !m_mapLayers.contains(sLayerId)) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
nmVTKRenderLayer* pLayer = m_mapLayers.take(sLayerId);
|
|
|
if(pLayer != nullptr) {
|
|
|
// 删除前先从 Renderer 移除 Prop,避免留下悬空引用。
|
|
|
pLayer->detach();
|
|
|
pLayer->releaseSceneOwnership(this);
|
|
|
delete pLayer;
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
void nmVTKScene::clear()
|
|
|
{
|
|
|
Q_ASSERT(isSceneGuiThread());
|
|
|
if(!isSceneGuiThread()) {
|
|
|
return;
|
|
|
}
|
|
|
clearLayers();
|
|
|
}
|
|
|
|
|
|
void nmVTKScene::clearLayers()
|
|
|
{
|
|
|
// 先从所有权容器摘除,再 detach 和 delete,避免析构回调重入时重复命中。
|
|
|
while(!m_mapLayers.isEmpty()) {
|
|
|
QMap<QString, nmVTKRenderLayer*>::iterator oIterator =
|
|
|
m_mapLayers.begin();
|
|
|
nmVTKRenderLayer* pLayer = oIterator.value();
|
|
|
m_mapLayers.erase(oIterator);
|
|
|
if(pLayer != nullptr) {
|
|
|
pLayer->detach();
|
|
|
pLayer->releaseSceneOwnership(this);
|
|
|
delete pLayer;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
int nmVTKScene::getLayerCount() const
|
|
|
{
|
|
|
Q_ASSERT(isSceneGuiThread());
|
|
|
return isSceneGuiThread() ? m_mapLayers.size() : 0;
|
|
|
}
|