#include "nmPebiResultWellAnnotationLayer.h" #include "nmPebiResultSnapshot.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { bool isWellAnnotationGuiThread() { QCoreApplication* pApplication = QCoreApplication::instance(); return pApplication == nullptr || pApplication->thread() == QThread::currentThread(); } } nmPebiResultWellAnnotationLayer::nmPebiResultWellAnnotationLayer( const QString& sLayerId) : nmVTKRenderLayer(sLayerId), m_pRootAssembly(vtkSmartPointer::New()), m_pActiveSnapshotAssembly(nullptr), m_pActiveMarkerGroup(nullptr), m_pActiveNameGroup(nullptr), m_pCandidateSnapshotAssembly(nullptr), m_pCandidateMarkerGroup(nullptr), m_pCandidateNameGroup(nullptr), m_bWellMarkersVisible(true), m_bWellNamesVisible(true) { Q_ASSERT(isWellAnnotationGuiThread()); // setRenderProp 只在未挂载时可调用,因此根 Assembly 在构造时一次固定。 setRenderProp(m_pRootAssembly); } nmPebiResultWellAnnotationLayer::~nmPebiResultWellAnnotationLayer() { Q_ASSERT(isWellAnnotationGuiThread()); detach(); clear(); m_pRootAssembly = nullptr; } bool nmPebiResultWellAnnotationLayer::prepareCandidate( const QSharedPointer& pSnapshot) { Q_ASSERT(isWellAnnotationGuiThread()); discardCandidate(); if(!isWellAnnotationGuiThread() || pSnapshot.isNull() || !pSnapshot->isComplete()) { return false; } vtkSmartPointer pMarkerPoints = vtkSmartPointer::New(); vtkSmartPointer pMarkerVertices = vtkSmartPointer::New(); vtkSmartPointer pNamePoints = vtkSmartPointer::New(); vtkSmartPointer pWellNames = vtkSmartPointer::New(); pWellNames->SetName("WellName"); QSet setWellIds; for(int nIndex = 0; nIndex < pSnapshot->getWellCount(); ++nIndex) { const nmPebiResultWellSnapshot* pWell = pSnapshot->getWellAt(nIndex); if(pWell == nullptr || pWell->m_sWellInstanceId.isEmpty() || pWell->m_sWellName.isEmpty() || !vtkMath::IsFinite(pWell->m_oLocation.x()) || !vtkMath::IsFinite(pWell->m_oLocation.y()) || setWellIds.contains(pWell->m_sWellInstanceId)) { discardCandidate(); return false; } setWellIds.insert(pWell->m_sWellInstanceId); // 保持快照存储顺序;二维 Overlay 不向业务位置写入虚构 Z 值。 const vtkIdType nPointId = pMarkerPoints->InsertNextPoint( pWell->m_oLocation.x(), pWell->m_oLocation.y(), 0.0); pMarkerVertices->InsertNextCell(1); pMarkerVertices->InsertCellPoint(nPointId); pNamePoints->InsertNextPoint( pWell->m_oLocation.x(), pWell->m_oLocation.y(), 0.0); const QByteArray aWellName = pWell->m_sWellName.toUtf8(); pWellNames->InsertNextValue(aWellName.constData()); } vtkSmartPointer pSnapshotAssembly = vtkSmartPointer::New(); vtkSmartPointer pMarkerGroup = vtkSmartPointer::New(); vtkSmartPointer pNameGroup = vtkSmartPointer::New(); if(pSnapshot->getWellCount() > 0) { vtkSmartPointer pMarkerData = vtkSmartPointer::New(); pMarkerData->SetPoints(pMarkerPoints); pMarkerData->SetVerts(pMarkerVertices); vtkSmartPointer pWorldCoordinate = vtkSmartPointer::New(); pWorldCoordinate->SetCoordinateSystemToWorld(); vtkSmartPointer pMarkerMapper = vtkSmartPointer::New(); pMarkerMapper->SetInputData(pMarkerData); pMarkerMapper->SetTransformCoordinate(pWorldCoordinate); pMarkerMapper->ScalarVisibilityOff(); vtkSmartPointer pMarkerActor = vtkSmartPointer::New(); pMarkerActor->SetMapper(pMarkerMapper); pMarkerActor->GetProperty()->SetColor(0.12, 0.12, 0.12); pMarkerActor->GetProperty()->SetPointSize(9.0); pMarkerGroup->AddPart(pMarkerActor); vtkSmartPointer pNameData = vtkSmartPointer::New(); pNameData->SetPoints(pNamePoints); pNameData->GetPointData()->AddArray(pWellNames); vtkSmartPointer pNameMapper = vtkSmartPointer::New(); pNameMapper->SetInputData(pNameData); pNameMapper->SetLabelModeToLabelFieldData(); pNameMapper->SetFieldDataName("WellName"); pNameMapper->SetLabelFormat("%s"); pNameMapper->GetLabelTextProperty()->SetFontSize(12); pNameMapper->GetLabelTextProperty()->SetColor(0.10, 0.10, 0.10); pNameMapper->GetLabelTextProperty()->BoldOff(); pNameMapper->GetLabelTextProperty()->ItalicOff(); pNameMapper->GetLabelTextProperty()->ShadowOff(); pNameMapper->GetLabelTextProperty()->SetJustificationToLeft(); pNameMapper->GetLabelTextProperty()->SetVerticalJustificationToBottom(); vtkSmartPointer pNameActor = vtkSmartPointer::New(); pNameActor->SetMapper(pNameMapper); // Actor2D 的显示坐标偏移固定为像素,不随相机缩放改变。 pNameActor->SetDisplayPosition(7, 6); pNameGroup->AddPart(pNameActor); } pMarkerGroup->SetVisibility(m_bWellMarkersVisible ? 1 : 0); pNameGroup->SetVisibility(m_bWellNamesVisible ? 1 : 0); pSnapshotAssembly->AddPart(pMarkerGroup); pSnapshotAssembly->AddPart(pNameGroup); // 所有校验和 VTK 对象构造成功后才记录候选;活动子树仍未触碰。 m_pCandidateSnapshotAssembly = pSnapshotAssembly; m_pCandidateMarkerGroup = pMarkerGroup; m_pCandidateNameGroup = pNameGroup; return true; } void nmPebiResultWellAnnotationLayer::discardCandidate() { Q_ASSERT(isWellAnnotationGuiThread()); m_pCandidateNameGroup = nullptr; m_pCandidateMarkerGroup = nullptr; m_pCandidateSnapshotAssembly = nullptr; } void nmPebiResultWellAnnotationLayer::commitCandidate() { Q_ASSERT(isWellAnnotationGuiThread()); Q_ASSERT(m_pCandidateSnapshotAssembly != nullptr); if(m_pActiveSnapshotAssembly != nullptr) { m_pRootAssembly->RemovePart(m_pActiveSnapshotAssembly); } m_pActiveSnapshotAssembly = m_pCandidateSnapshotAssembly; m_pActiveMarkerGroup = m_pCandidateMarkerGroup; m_pActiveNameGroup = m_pCandidateNameGroup; m_pRootAssembly->AddPart(m_pActiveSnapshotAssembly); discardCandidate(); } void nmPebiResultWellAnnotationLayer::clear() { Q_ASSERT(isWellAnnotationGuiThread()); discardCandidate(); if(m_pRootAssembly != nullptr && m_pActiveSnapshotAssembly != nullptr) { m_pRootAssembly->RemovePart(m_pActiveSnapshotAssembly); } m_pActiveNameGroup = nullptr; m_pActiveMarkerGroup = nullptr; m_pActiveSnapshotAssembly = nullptr; } bool nmPebiResultWellAnnotationLayer::hasActiveAnnotations() const { return m_pActiveSnapshotAssembly != nullptr; } void nmPebiResultWellAnnotationLayer::setWellMarkersVisible(bool bVisible) { Q_ASSERT(isWellAnnotationGuiThread()); if(!isWellAnnotationGuiThread()) { return; } m_bWellMarkersVisible = bVisible; if(m_pActiveMarkerGroup != nullptr) { m_pActiveMarkerGroup->SetVisibility(bVisible ? 1 : 0); } if(m_pCandidateMarkerGroup != nullptr) { m_pCandidateMarkerGroup->SetVisibility(bVisible ? 1 : 0); } } void nmPebiResultWellAnnotationLayer::setWellNamesVisible(bool bVisible) { Q_ASSERT(isWellAnnotationGuiThread()); if(!isWellAnnotationGuiThread()) { return; } m_bWellNamesVisible = bVisible; if(m_pActiveNameGroup != nullptr) { m_pActiveNameGroup->SetVisibility(bVisible ? 1 : 0); } if(m_pCandidateNameGroup != nullptr) { m_pCandidateNameGroup->SetVisibility(bVisible ? 1 : 0); } } bool nmPebiResultWellAnnotationLayer::areWellMarkersVisible() const { return m_bWellMarkersVisible; } bool nmPebiResultWellAnnotationLayer::areWellNamesVisible() const { return m_bWellNamesVisible; }