#include "nmVTKRotationCenterMarkerLayer.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { const double ROTATION_CENTER_HALF_LENGTH_PIXELS = 18.0; const double ROTATION_CENTER_DEPTH_OFFSET_PIXELS = 1.5; const double ROTATION_CENTER_HOMOGENEOUS_EPSILON = std::numeric_limits::epsilon(); bool isRotationCenterMarkerGuiThread() { QCoreApplication* pApplication = QCoreApplication::instance(); return pApplication == nullptr || pApplication->thread() == QThread::currentThread(); } bool isFinitePoint3(const double dPoint[3]) { return dPoint != nullptr && vtkMath::IsFinite(dPoint[0]) && vtkMath::IsFinite(dPoint[1]) && vtkMath::IsFinite(dPoint[2]); } bool worldToDisplay(vtkRenderer* pRenderer, const double dWorld[3], double dDisplay[3]) { if(pRenderer == nullptr || dWorld == nullptr || dDisplay == nullptr) { return false; } pRenderer->SetWorldPoint(dWorld[0], dWorld[1], dWorld[2], 1.0); pRenderer->WorldToDisplay(); const double* pDisplay = pRenderer->GetDisplayPoint(); if(!isFinitePoint3(pDisplay)) { return false; } dDisplay[0] = pDisplay[0]; dDisplay[1] = pDisplay[1]; dDisplay[2] = pDisplay[2]; return true; } bool displayToWorld(vtkRenderer* pRenderer, const double dDisplay[3], double dWorld[3]) { if(pRenderer == nullptr || dDisplay == nullptr || dWorld == nullptr || !isFinitePoint3(dDisplay)) { return false; } pRenderer->SetDisplayPoint( dDisplay[0], dDisplay[1], dDisplay[2]); pRenderer->DisplayToWorld(); const double* pHomogeneousWorld = pRenderer->GetWorldPoint(); if(pHomogeneousWorld == nullptr || !vtkMath::IsFinite(pHomogeneousWorld[0]) || !vtkMath::IsFinite(pHomogeneousWorld[1]) || !vtkMath::IsFinite(pHomogeneousWorld[2]) || !vtkMath::IsFinite(pHomogeneousWorld[3]) || std::fabs(pHomogeneousWorld[3]) <= ROTATION_CENTER_HOMOGENEOUS_EPSILON) { return false; } const double dInverseW = 1.0 / pHomogeneousWorld[3]; dWorld[0] = pHomogeneousWorld[0] * dInverseW; dWorld[1] = pHomogeneousWorld[1] * dInverseW; dWorld[2] = pHomogeneousWorld[2] * dInverseW; return isFinitePoint3(dWorld); } } class nmVTKRotationCenterMarkerLayerPrivate { public: nmVTKRotationCenterMarkerLayerPrivate() : m_pPoints(vtkSmartPointer::New()), m_pLines(vtkSmartPointer::New()), m_pColors(vtkSmartPointer::New()), m_pPolyData(vtkSmartPointer::New()), m_pMapper(vtkSmartPointer::New()), m_pActor(vtkSmartPointer::New()), m_pRendererCallback(vtkSmartPointer::New()), m_pCameraCallback(vtkSmartPointer::New()), m_pRenderer(nullptr), m_pCamera(nullptr), m_nRendererObserverTag(0), m_nCameraObserverTag(0), m_bHasWorldCenter(false) { // 必须通过 vtkActor::New() 的对象工厂路径获得实际 OpenGL Actor。 initializeGeometry(); m_dWorldCenter[0] = 0.0; m_dWorldCenter[1] = 0.0; m_dWorldCenter[2] = 0.0; m_pRendererCallback->SetClientData(this); m_pRendererCallback->SetCallback( nmVTKRotationCenterMarkerLayerPrivate::rendererStarted); m_pCameraCallback->SetClientData(this); m_pCameraCallback->SetCallback( nmVTKRotationCenterMarkerLayerPrivate::cameraModified); } ~nmVTKRotationCenterMarkerLayerPrivate() { // 先移除 Renderer 和 Camera Observer,再阻断裸回调目标。 unbindRenderer(); m_pRendererCallback->SetClientData(nullptr); m_pRendererCallback->SetCallback(nullptr); m_pCameraCallback->SetClientData(nullptr); m_pCameraCallback->SetCallback(nullptr); } vtkActor* getActor() const { return m_pActor; } bool bindRenderer(vtkRenderer* pRenderer) { if(pRenderer == nullptr) { return false; } if(m_pRenderer.GetPointer() != pRenderer) { unbindRenderer(); m_pRenderer = pRenderer; } if(!ensureRendererObserver(pRenderer) || !ensureCameraObserver(pRenderer->GetActiveCamera())) { unbindRenderer(); return false; } return true; } void unbindRenderer() { removeCameraObserver(); removeRendererObserver(); m_pRenderer = nullptr; } bool synchronize() { return synchronizeForRenderer(m_pRenderer.GetPointer()); } bool synchronizeForRenderer(vtkRenderer* pRenderer) { if(pRenderer == nullptr || m_pRenderer.GetPointer() != pRenderer || !m_bHasWorldCenter) { return false; } vtkCamera* pCamera = pRenderer->GetActiveCamera(); if(pCamera == nullptr || !ensureCameraObserver(pCamera)) { return false; } int* pViewportSize = pRenderer->GetSize(); if(pViewportSize == nullptr || pViewportSize[0] <= 0 || pViewportSize[1] <= 0) { return false; } const double dLogicalCenter[3] = { m_dWorldCenter[0], m_dWorldCenter[1], m_dWorldCenter[2] }; double dCameraPosition[3]; pCamera->GetPosition(dCameraPosition); if(!isFinitePoint3(dLogicalCenter) || !isFinitePoint3(dCameraPosition)) { return false; } double dCenterDisplay[3]; if(!worldToDisplay(pRenderer, dLogicalCenter, dCenterDisplay)) { return false; } double dOffsetDisplay[3] = { dCenterDisplay[0], dCenterDisplay[1] + ROTATION_CENTER_HALF_LENGTH_PIXELS, dCenterDisplay[2] }; double dCenterAtDepth[3]; double dOffsetAtDepth[3]; if(!displayToWorld(pRenderer, dCenterDisplay, dCenterAtDepth) || !displayToWorld(pRenderer, dOffsetDisplay, dOffsetAtDepth)) { return false; } const double dScaleX = dOffsetAtDepth[0] - dCenterAtDepth[0]; const double dScaleY = dOffsetAtDepth[1] - dCenterAtDepth[1]; const double dScaleZ = dOffsetAtDepth[2] - dCenterAtDepth[2]; const double dHalfLength = std::sqrt( dScaleX * dScaleX + dScaleY * dScaleY + dScaleZ * dScaleZ); if(!vtkMath::IsFinite(dHalfLength) || dHalfLength <= 0.0) { return false; } double dTowardCamera[3]; if(pCamera->GetParallelProjection() != 0) { const double* pDirectionOfProjection = pCamera->GetDirectionOfProjection(); if(!isFinitePoint3(pDirectionOfProjection)) { return false; } dTowardCamera[0] = -pDirectionOfProjection[0]; dTowardCamera[1] = -pDirectionOfProjection[1]; dTowardCamera[2] = -pDirectionOfProjection[2]; } else { dTowardCamera[0] = dCameraPosition[0] - dLogicalCenter[0]; dTowardCamera[1] = dCameraPosition[1] - dLogicalCenter[1]; dTowardCamera[2] = dCameraPosition[2] - dLogicalCenter[2]; } if(vtkMath::Normalize(dTowardCamera) <= 0.0) { return false; } const double dWorldPerPixel = dHalfLength / ROTATION_CENTER_HALF_LENGTH_PIXELS; const double dDepthOffset = dWorldPerPixel * ROTATION_CENTER_DEPTH_OFFSET_PIXELS; const double dDisplayCenter[3] = { dLogicalCenter[0] + dTowardCamera[0] * dDepthOffset, dLogicalCenter[1] + dTowardCamera[1] * dDepthOffset, dLogicalCenter[2] + dTowardCamera[2] * dDepthOffset }; const double dAxisPoints[6][3] = { { dDisplayCenter[0] - dHalfLength, dDisplayCenter[1], dDisplayCenter[2] }, { dDisplayCenter[0] + dHalfLength, dDisplayCenter[1], dDisplayCenter[2] }, { dDisplayCenter[0], dDisplayCenter[1] - dHalfLength, dDisplayCenter[2] }, { dDisplayCenter[0], dDisplayCenter[1] + dHalfLength, dDisplayCenter[2] }, { dDisplayCenter[0], dDisplayCenter[1], dDisplayCenter[2] - dHalfLength }, { dDisplayCenter[0], dDisplayCenter[1], dDisplayCenter[2] + dHalfLength } }; for(vtkIdType nPoint = 0; nPoint < 6; ++nPoint) { if(!isFinitePoint3(dAxisPoints[nPoint])) { return false; } } for(vtkIdType nPoint = 0; nPoint < 6; ++nPoint) { m_pPoints->SetPoint(nPoint, dAxisPoints[nPoint]); } m_pPoints->Modified(); m_pPolyData->Modified(); return true; } bool setWorldCenter(double dX, double dY, double dZ) { const double dCenter[3] = { dX, dY, dZ }; if(!isFinitePoint3(dCenter)) { return false; } m_dWorldCenter[0] = dX; m_dWorldCenter[1] = dY; m_dWorldCenter[2] = dZ; m_bHasWorldCenter = true; synchronize(); return true; } bool hasWorldCenter() const { return m_bHasWorldCenter; } private: static void rendererStarted(vtkObject* pCaller, unsigned long, void* pClientData, void*) { nmVTKRotationCenterMarkerLayerPrivate* pThis = static_cast( pClientData); if(pThis != nullptr) { // StartEvent 位于 Prop 遍历之前,可使用最终视口尺寸覆盖 Resize 路径。 pThis->synchronizeForRenderer( vtkRenderer::SafeDownCast(pCaller)); } } static void cameraModified(vtkObject*, unsigned long, void* pClientData, void*) { nmVTKRotationCenterMarkerLayerPrivate* pThis = static_cast( pClientData); if(pThis != nullptr) { // 相机回调只同步几何,最终 Render 仍由交互器或容器统一提交。 pThis->synchronize(); } } void initializeGeometry() { m_pPoints->SetDataTypeToDouble(); m_pPoints->SetNumberOfPoints(6); for(vtkIdType nPoint = 0; nPoint < 6; ++nPoint) { m_pPoints->SetPoint(nPoint, 0.0, 0.0, 0.0); } for(vtkIdType nAxis = 0; nAxis < 3; ++nAxis) { vtkIdType nPointIds[2] = { nAxis * 2, nAxis * 2 + 1 }; m_pLines->InsertNextCell(2, nPointIds); } m_pColors->SetName("RotationCenterAxisColors"); m_pColors->SetNumberOfComponents(3); m_pColors->InsertNextTuple3(255.0, 0.0, 0.0); m_pColors->InsertNextTuple3(254.0, 255.0, 0.0); m_pColors->InsertNextTuple3(0.0, 255.0, 0.0); m_pPolyData->SetPoints(m_pPoints); m_pPolyData->SetLines(m_pLines); m_pPolyData->GetCellData()->SetScalars(m_pColors); m_pMapper->SetInputData(m_pPolyData); m_pMapper->ScalarVisibilityOn(); m_pMapper->SetScalarModeToUseCellData(); m_pMapper->SetColorModeToDirectScalars(); m_pActor->SetMapper(m_pMapper); m_pActor->GetProperty()->SetLineWidth(1.0f); m_pActor->GetProperty()->SetOpacity(1.0); m_pActor->GetProperty()->LightingOff(); m_pActor->PickableOff(); m_pActor->UseBoundsOff(); } bool ensureRendererObserver(vtkRenderer* pRenderer) { if(pRenderer == nullptr || m_pRendererCallback == nullptr) { return false; } if(m_pRenderer.GetPointer() == pRenderer && m_nRendererObserverTag != 0) { return true; } removeRendererObserver(); m_nRendererObserverTag = pRenderer->AddObserver( vtkCommand::StartEvent, m_pRendererCallback); return m_nRendererObserverTag != 0; } void removeRendererObserver() { vtkRenderer* pRenderer = m_pRenderer.GetPointer(); if(pRenderer != nullptr && m_nRendererObserverTag != 0) { pRenderer->RemoveObserver(m_nRendererObserverTag); } m_nRendererObserverTag = 0; } bool ensureCameraObserver(vtkCamera* pCamera) { if(pCamera == nullptr || m_pCameraCallback == nullptr) { return false; } if(m_pCamera.GetPointer() == pCamera && m_nCameraObserverTag != 0) { return true; } removeCameraObserver(); m_pCamera = pCamera; m_nCameraObserverTag = pCamera->AddObserver( vtkCommand::ModifiedEvent, m_pCameraCallback); if(m_nCameraObserverTag == 0) { m_pCamera = nullptr; return false; } return true; } void removeCameraObserver() { vtkCamera* pCamera = m_pCamera.GetPointer(); if(pCamera != nullptr && m_nCameraObserverTag != 0) { pCamera->RemoveObserver(m_nCameraObserverTag); } m_nCameraObserverTag = 0; m_pCamera = nullptr; } vtkSmartPointer m_pPoints; vtkSmartPointer m_pLines; vtkSmartPointer m_pColors; vtkSmartPointer m_pPolyData; vtkSmartPointer m_pMapper; vtkSmartPointer m_pActor; vtkSmartPointer m_pRendererCallback; vtkSmartPointer m_pCameraCallback; vtkWeakPointer m_pRenderer; ///< 非所有权引用。 vtkWeakPointer m_pCamera; ///< 非所有权引用。 unsigned long m_nRendererObserverTag; ///< 为零表示尚未注册观察者。 unsigned long m_nCameraObserverTag; ///< 为零表示尚未注册观察者。 double m_dWorldCenter[3]; ///< 独立于相机焦点的逻辑中心。 bool m_bHasWorldCenter; }; nmVTKRotationCenterMarkerLayer::nmVTKRotationCenterMarkerLayer( const QString& sLayerId) : nmVTKRenderLayer(sLayerId), m_pPrivate(new nmVTKRotationCenterMarkerLayerPrivate) { Q_ASSERT(isRotationCenterMarkerGuiThread()); setRenderProp(m_pPrivate->getActor()); setVisible(false); } nmVTKRotationCenterMarkerLayer::~nmVTKRotationCenterMarkerLayer() { Q_ASSERT(isRotationCenterMarkerGuiThread()); if(m_pPrivate != nullptr) { // Renderer/Camera Observer 必须在 Renderer 和回调目标释放前解除。 m_pPrivate->unbindRenderer(); detach(); delete m_pPrivate; m_pPrivate = nullptr; } } bool nmVTKRotationCenterMarkerLayer::bindRenderer(vtkRenderer* pRenderer) { Q_ASSERT(isRotationCenterMarkerGuiThread()); if(!isRotationCenterMarkerGuiThread() || m_pPrivate == nullptr || pRenderer == nullptr || getAttachedRenderer() != pRenderer) { return false; } return m_pPrivate->bindRenderer(pRenderer); } void nmVTKRotationCenterMarkerLayer::unbindRenderer() { Q_ASSERT(isRotationCenterMarkerGuiThread()); if(isRotationCenterMarkerGuiThread() && m_pPrivate != nullptr) { m_pPrivate->unbindRenderer(); } } bool nmVTKRotationCenterMarkerLayer::synchronize() { Q_ASSERT(isRotationCenterMarkerGuiThread()); return isRotationCenterMarkerGuiThread() && m_pPrivate != nullptr && m_pPrivate->synchronize(); } bool nmVTKRotationCenterMarkerLayer::setWorldCenter( double dX, double dY, double dZ) { Q_ASSERT(isRotationCenterMarkerGuiThread()); return isRotationCenterMarkerGuiThread() && m_pPrivate != nullptr && m_pPrivate->setWorldCenter(dX, dY, dZ); } bool nmVTKRotationCenterMarkerLayer::hasWorldCenter() const { return m_pPrivate != nullptr && m_pPrivate->hasWorldCenter(); } void nmVTKRotationCenterMarkerLayer::setMarkerVisible(bool bVisible) { Q_ASSERT(isRotationCenterMarkerGuiThread()); if(!isRotationCenterMarkerGuiThread()) { return; } const bool bCanShow = bVisible && m_pPrivate != nullptr && m_pPrivate->hasWorldCenter(); setVisible(bCanShow); if(bCanShow) { // 首次显示先准备几何;视口尚未建立时由绘制前同步再次补齐。 m_pPrivate->synchronize(); } } bool nmVTKRotationCenterMarkerLayer::isMarkerVisible() const { return isVisible(); }