#include "nmVTKScene.h" #include "nmVTKRenderLayer.h" #include #include #include namespace { // Release 构建也会通过返回值拒绝跨线程操作,断言用于尽早暴露调用错误。 bool isSceneGuiThread() { QCoreApplication* pApplication = QCoreApplication::instance(); return pApplication == NULL || 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 = NULL; } bool nmVTKScene::addLayer(nmVTKRenderLayer* pLayer) { Q_ASSERT(isSceneGuiThread()); if(!isSceneGuiThread() || pLayer == NULL || m_pRenderer == NULL) { 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 NULL; } return m_mapLayers.value(sLayerId, NULL); } 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 != NULL) { // 删除前先从 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::iterator oIterator = m_mapLayers.begin(); nmVTKRenderLayer* pLayer = oIterator.value(); m_mapLayers.erase(oIterator); if(pLayer != NULL) { pLayer->detach(); pLayer->releaseSceneOwnership(this); delete pLayer; } } } int nmVTKScene::getLayerCount() const { Q_ASSERT(isSceneGuiThread()); return isSceneGuiThread() ? m_mapLayers.size() : 0; }