diff --git a/Include/nmNum/nmPlot/nmObjPointWell.h b/Include/nmNum/nmPlot/nmObjPointWell.h index ea27ad8..23621d9 100644 --- a/Include/nmNum/nmPlot/nmObjPointWell.h +++ b/Include/nmNum/nmPlot/nmObjPointWell.h @@ -3,11 +3,10 @@ #include "nmObjPoint.h" #include "nmDefines.h" #include "nmPlot_global.h" -#include "ZxDataWell.h" -#include "ZxObjText.h" -class nmDataWellBase; class nmPlotGraphicBinder; +class ZxDataWell; +class ZxObjText; // 数值试井绘图对象(点) class NM_PLOT_EXPORT nmObjPointWell : public nmObjPoint { @@ -75,13 +74,10 @@ class NM_PLOT_EXPORT nmObjPointWell : public nmObjPoint { // 删除当前对象里的参数对象 virtual void removeData() override; - // 设置当前井来自数据中心的井数据 - void setNmWellData(nmDataWellBase* wellData); - // 获取当前井数据 - nmDataWellBase* getNmWellData(); - void setGraphicBinder(nmPlotGraphicBinder* pBinder) { m_pGraphicBinder = pBinder; } nmPlotGraphicBinder* getGraphicBinder() const { return m_pGraphicBinder; } + // 标记井数据已由Binder绑定,图元只保留井类型 + void markWellDataBound(NM_WELL_MODEL wellType); public slots: // 图元状态改变 @@ -97,9 +93,6 @@ class NM_PLOT_EXPORT nmObjPointWell : public nmObjPoint { ZxObjText* m_pNameLabel; bool m_bSelectWell; QString m_sWellID; - ZxDataWell* m_pWellData; - - nmDataWellBase* m_pNmWellData; // 自定义井数据 nmPlotGraphicBinder* m_pGraphicBinder; // 图元-数据绑定协调器 diff --git a/Include/nmNum/nmPlot/nmPlotGraphicBinder.h b/Include/nmNum/nmPlot/nmPlotGraphicBinder.h index a636c62..7ddeee4 100644 --- a/Include/nmNum/nmPlot/nmPlotGraphicBinder.h +++ b/Include/nmNum/nmPlot/nmPlotGraphicBinder.h @@ -3,6 +3,9 @@ #include #include #include +#include +#include +#include #include "nmPlot_global.h" #include "nmDefines.h" @@ -25,6 +28,8 @@ class nmDataRegion; class nmObjRegion; class nmDataWellBase; class nmObjPointWell; +class ZxDataWell; +class ZxObjText; // 图元与数据绑定协调器,由 nmGuiPlot 托管 class NM_PLOT_EXPORT nmPlotGraphicBinder : public QObject @@ -148,6 +153,35 @@ public: // 查找井图元对应的数据指针 nmDataWellBase* getWellDataFor(nmObjPointWell* pGraphic); + // 井图元绘制所需的只读数据快照 + struct WellRenderData { + WellRenderData(); + bool valid; + NM_WELL_MODEL wellType; + double x; + double y; + double radius; + double wellLength; + double drainAngle; + QVector verticalFracs; + QVector> horizontalFracs; + }; + + // 判断井图元是否已绑定井数据 + bool hasWellDataFor(nmObjPointWell* pGraphic) const; + // 判断井图元是否为当前分析井 + bool isCurrentWellGraphic(nmObjPointWell* pGraphic) const; + // 图元移动后,同步井位置及裂缝位置 + void syncWellMoveFromGraphic(nmObjPointWell* pGraphic, NM_WELL_MODEL wellType, const QPointF& newLocation); + // 选择已有井后,确保图元已创建并绑定对应的井数据 + bool ensureSelectedWellData(nmObjPointWell* pGraphic, NM_WELL_MODEL& wellType); + // 编辑井属性,并将结果同步到框架井数据和数值井数据 + bool editWellForGraphic(nmObjPointWell* pGraphic, NM_WELL_MODEL& wellType, ZxObjText* pNameLabel); + // 获取井图元绘制所需的数据快照 + WellRenderData getWellRenderData(nmObjPointWell* pGraphic) const; + // 同步井图元可见性到井数据 + void setWellVisible(nmObjPointWell* pGraphic, bool bVisible); + // 更新井图元的数据映射(编辑井后更换数据对象时使用) void updateWellDataMapping(nmObjPointWell* pGraphic, nmDataWellBase* pNewData) { m_mapWellData[pGraphic] = pNewData; } diff --git a/Src/nmNum/nmPlot/nmGuiPlot.cpp b/Src/nmNum/nmPlot/nmGuiPlot.cpp index b543b42..d26acde 100644 --- a/Src/nmNum/nmPlot/nmGuiPlot.cpp +++ b/Src/nmNum/nmPlot/nmGuiPlot.cpp @@ -57,6 +57,8 @@ #include "nmPlotGraphicBinder.h" +#include "ZxDataWell.h" + #include "ZxDataGaugeP.h" #include "ZxDataGaugeF.h" @@ -900,7 +902,7 @@ void nmGuiPlot::slotDeleteWell(QString wellID) } // 当前井作为活动分析井保留,不允许从地图中直接删除 - if(obj->getNmWellData() == nmDataAnalyzeManager::getCurrentInstance()->getCurWellData()) { + if(m_pGraphicBinder && m_pGraphicBinder->isCurrentWellGraphic(obj)) { return; } @@ -1365,9 +1367,7 @@ void nmGuiPlot::slotDeleteOneObj(QString sName, void* obj) } if(nmObjPointWell* pWellObj = dynamic_cast(nmObj)) { - nmDataWellBase* pCurWell = nmDataAnalyzeManager::getCurrentInstance()->getCurWellData(); - - if(pWellObj->getNmWellData() == pCurWell) { + if(m_pGraphicBinder && m_pGraphicBinder->isCurrentWellGraphic(pWellObj)) { if(pDeleteTool) { m_pPlot->removeTools(pDeleteTool); } diff --git a/Src/nmNum/nmPlot/nmObjPointWell.cpp b/Src/nmNum/nmPlot/nmObjPointWell.cpp index 7f00cfd..ea216f4 100644 --- a/Src/nmNum/nmPlot/nmObjPointWell.cpp +++ b/Src/nmNum/nmPlot/nmObjPointWell.cpp @@ -10,6 +10,7 @@ #include "ZxPlot.h" #include "ZxObjText.h" +#include "ZxDataWell.h" #include "nmObjPointWellTool.h" #include "nmObjPointWell.h" @@ -17,7 +18,6 @@ #include "nmDataLogFile.h" #include "iWxWellNew.h" -#include "ZxBaseUtil.h" #include "ZxDataProject.h" #include "TreeWxMain.h" @@ -30,16 +30,6 @@ #include "nmPlotGraphicBinder.h" -#include "ZxDataGaugeP.h" -#include "ZxDataGaugeF.h" - -#include "nmPlotDialogContext.h" -#include "nmPlotDialogContextProvider.h" - -#include "nmDataVerticalFracturedWell.h" -#include "nmDataHorizontalFracturedWell.h" -#include "nmDataVerticalWell.h" -#include "nmDataWellBase.h" ZX_DEFINE_DYNAMIC(nObjPointWell, nmObjPointWell) @@ -47,8 +37,6 @@ nmObjPointWell::nmObjPointWell() : nmObjPoint() , m_pNameLabel(nullptr) , m_bSelectWell(false) - , m_pWellData(nullptr) - , m_pNmWellData(nullptr) , m_pGraphicBinder(nullptr) , m_enumWellType(NM_WELL_MODEL::Vertical_Well) { @@ -61,8 +49,6 @@ nmObjPointWell::nmObjPointWell(const QString& sName, \ : nmObjPoint(sName, pAxisX, pAxisY) , m_pNameLabel(nullptr) , m_bSelectWell(false) - , m_pWellData(nullptr) - , m_pNmWellData(nullptr) , m_pGraphicBinder(nullptr) , m_enumWellType(NM_WELL_MODEL::Vertical_Well) { @@ -71,8 +57,7 @@ nmObjPointWell::nmObjPointWell(const QString& sName, \ nmObjPointWell::~nmObjPointWell() { - // 井数据由DataManager统一释放,图元只保存引用。 - m_pNmWellData = nullptr; + // 井数据由 DataManager 和工程树统一管理,图元不持有数据指针。 } void nmObjPointWell::init(const QString& sName, \ @@ -91,7 +76,6 @@ void nmObjPointWell::init(const QString& sName, \ m_vecPoints << QPointF(0.f, 0.f); loadTempl(); - m_pNmWellData = nullptr; m_pGraphicBinder = nullptr; // 连接图元可见性信号和槽 @@ -110,32 +94,9 @@ bool nmObjPointWell::runMove(const QPointF &pt1, const QPointF &pt2) nmObjPoint::runMove(pt1, pt2); // 更新井的位置信息 - if(m_pWellData && m_pNmWellData) { + if(m_pGraphicBinder) { QPointF newLocation = this->getValueOf(pt2); - m_pWellData->setLocationX(newLocation.x()); - m_pWellData->setLocationY(newLocation.y()); - - // 更新井基础信息 - nmDataAttribute tempAttr = m_pNmWellData->getX(); - tempAttr.setValue(m_pWellData->getLocationX()); - m_pNmWellData->setX(tempAttr); - tempAttr = m_pNmWellData->getY(); - tempAttr.setValue(m_pWellData->getLocationY()); - m_pNmWellData->setY(tempAttr); - tempAttr = m_pNmWellData->getRadius(); - tempAttr.setValue(m_pWellData->getWellRadius()); - m_pNmWellData->setRadius(tempAttr); - - // 对于裂缝类型的井,需要更新裂缝位置 - if (m_enumWellType == NM_WELL_MODEL::Vertical_Fractured_Well) { - if (nmDataVerticalFracturedWell* pVFWell = dynamic_cast(m_pNmWellData)) { - pVFWell->setFracs(); - } - } else if (m_enumWellType == NM_WELL_MODEL::Horizontal_Fractured_Well) { - if (nmDataHorizontalFracturedWell* pHFWell = dynamic_cast(m_pNmWellData)) { - pHFWell->setFracs(); - } - } + m_pGraphicBinder->syncWellMoveFromGraphic(this, m_enumWellType, newLocation); } if (m_pGraphicBinder) { @@ -177,15 +138,12 @@ void nmObjPointWell::onDeserialize(ZxSerializer* ser) nmObjBase::onDeserialize(ser); ser->read("NMWellID", m_sWellID); // 根据wellID获取井的信息 - m_pWellData = nullptr; - if (zxCurProject != nullptr) { - m_pWellData = (ZxDataWell*)zxCurProject->getChild(iDataModelType::sTypeWell, m_sWellID); - } + ZxDataWell* pWellData = getWellData(); - if(m_pWellData) { + if(pWellData) { // 设置图元的位置信息,将井的坐标设置为plot对象的坐标 m_vecPoints.clear(); - m_vecPoints << QPointF(m_pWellData->getLocationX(), m_pWellData->getLocationY()); + m_vecPoints << QPointF(pWellData->getLocationX(), pWellData->getLocationY()); return; } @@ -203,15 +161,12 @@ void nmObjPointWell::onLoadTempl(ZxSerializer* ser) nmObjBase::onLoadTempl(ser); ser->read("NMWellID", m_sWellID); // 根据wellID获取井的信息 - m_pWellData = nullptr; - if (zxCurProject != nullptr) { - m_pWellData = (ZxDataWell*)zxCurProject->getChild(iDataModelType::sTypeWell, m_sWellID); - } + ZxDataWell* pWellData = getWellData(); - if(m_pWellData) { + if(pWellData) { // 设置图元的位置信息,将井的坐标设置为plot对象的坐标 m_vecPoints.clear(); - m_vecPoints << QPointF(m_pWellData->getLocationX(), m_pWellData->getLocationY()); + m_vecPoints << QPointF(pWellData->getLocationX(), pWellData->getLocationY()); return; } @@ -221,11 +176,12 @@ void nmObjPointWell::onLoadTempl(ZxSerializer* ser) void nmObjPointWell::afterCreated() { - if(m_pWellData) { + ZxDataWell* pWellData = getWellData(); + if(pWellData) { ZxPlot* pPlot = dynamic_cast(this->getParent()); if(NULL != pPlot) { - QString sName = m_pWellData->getName(); + QString sName = pWellData->getName(); this->setName(sName); ZxObjBase* p = pPlot->addOneObj(POT_Text, sName, false, \ m_pAxisX, m_pAxisY); @@ -254,144 +210,19 @@ void nmObjPointWell::afterCreated() // 如果是选择的井,则不弹出创建的dialog if(m_bSelectWell) { - // 判断是哪一种井类型,初始化对应的参数 - ZxDataWell* pWellData = m_pWellData; + // 选择已有井时,通过Binder初始化对应的井数据 if (pWellData == nullptr) { return; } - QString wellClass = m_pWellData->getWellClassEn(); - - // 获取当前井的压力、流量数据 - ZxDataObjectList m_listGaugeP = pWellData->getChildren(iDataModelType::sTypeDataGaugeP); - ZxDataObjectList m_listGaugeF = pWellData->getChildren(iDataModelType::sTypeDataGaugeF); - - ZxDataGaugeP* pGaugeP = nullptr; - ZxDataGaugeF* pGaugeF = nullptr; - - // 遍历压力数据列表 - for(int i = 0; i < m_listGaugeP.size(); ++i) { - if(pGaugeP = dynamic_cast(m_listGaugeP[i])) { // 拿到第一条压力数据 - break; - } - } - - // 遍历流量数据列表 - for(int i = 0; i < m_listGaugeF.size(); ++i) { - if(pGaugeF = dynamic_cast(m_listGaugeF[i])) { // 拿到第一条流量数据 - break; - } - } - - // 获取的压力、流量数据 - QVector vecPtsP, vecPtsF; - vecPtsP.clear(); - vecPtsF.clear(); - // 临时存储x,y坐标 - VecDouble vecX, vecY; - - if(pGaugeP != nullptr) { - // 获取压力数据 - if(pGaugeP->getDataVecXY(vecX, vecY)) { - for(int i = 0; i < vecX.size(); ++i) { - if(i < vecY.size()) { - QPointF pt(vecX[i], vecY[i]); - vecPtsP.append(pt); - } - } - } - } - - if(pGaugeF != nullptr) { - vecX.clear(); - vecY.clear(); - - // 获取流量数据 - if(pGaugeF->getDataVecXY(vecX, vecY)) { - for(int i = 0; i < vecX.size(); ++i) { - if(i < vecY.size()) { - QPointF pt(vecX[i], vecY[i]); - vecPtsF.append(pt); - } - } - } - } - - int nIndexF = -2; //当前井的流动段索引 - - // 判断是否为当前井 - if(m_pWellData != zxCurWell) { - // 更新当前井的流动段的索引,默认为最后一段 - nIndexF = vecPtsF.count() - 1; - } - - if(ZxBaseUtil::isSameStr(wellClass, "VerticalWell")) { - // 切换当前井类型 - m_enumWellType = NM_WELL_MODEL::Vertical_Well; - } else if(ZxBaseUtil::isSameStr(wellClass, "VerticalFracturedWell")) { - // 切换当前井类型 - m_enumWellType = NM_WELL_MODEL::Vertical_Fractured_Well; - } else if(ZxBaseUtil::isSameStr(wellClass, "HorizontalFracturedWell")) { - // 切换当前井类型 - m_enumWellType = NM_WELL_MODEL::Horizontal_Fractured_Well; - } else { + if (m_pGraphicBinder == nullptr || + !m_pGraphicBinder->ensureSelectedWellData(this, m_enumWellType)) { return; } - // 如果已有井数据(文件加载时通过 bindWellToGraphic 绑定),则跳过创建 - if (m_pNmWellData == nullptr) { - m_pNmWellData = m_pGraphicBinder->createWellForGraphic(this, m_enumWellType); - if (m_pNmWellData == nullptr) { - return; - } - - m_pNmWellData->setWellName(m_pWellData->getName()); - nmDataAttribute tempAttr = m_pNmWellData->getX(); - tempAttr.setValue(m_pWellData->getLocationX()); - m_pNmWellData->setX(tempAttr); - tempAttr = m_pNmWellData->getY(); - tempAttr.setValue(m_pWellData->getLocationY()); - m_pNmWellData->setY(tempAttr); - tempAttr = m_pNmWellData->getRadius(); - tempAttr.setValue(m_pWellData->getWellRadius()); - m_pNmWellData->setRadius(tempAttr); - - // 设置井的压力数据、流量数据 - m_pNmWellData->setPressurePoints(vecPtsP); - m_pNmWellData->setFlowPoints(vecPtsF); - - // 设置井的流动段,默认为最后一段 - if(nIndexF >= -1) { - m_pNmWellData->setIndexF(nIndexF); - } - - // 对于裂缝类型的井,需要更新裂缝位置 - if (m_enumWellType == NM_WELL_MODEL::Vertical_Fractured_Well) { - if (nmDataVerticalFracturedWell* pVFWell = dynamic_cast(m_pNmWellData)) { - pVFWell->setFracs(); - } - } else if (m_enumWellType == NM_WELL_MODEL::Horizontal_Fractured_Well) { - if (nmDataHorizontalFracturedWell* pHFWell = dynamic_cast(m_pNmWellData)) { - pHFWell->setFracs(); - } - } - - // TODO: 计算井的历史双对数/半对数数据 - QVector> vvecHistoryPressureData; - QVector> vvecHistoryLogData; - QVector> vvecHistorySemiLogData; - - m_pGraphicBinder->calculateWellLogData(m_pNmWellData, vvecHistoryPressureData, vvecHistoryLogData, vvecHistorySemiLogData); - - // 存储历史数据到井对象 - m_pNmWellData->setHistoryPressure(vvecHistoryPressureData); - m_pNmWellData->setHistoryLogLog(vvecHistoryLogData); - m_pNmWellData->setHistorySemiLog(vvecHistorySemiLogData); - } - return; } - if(m_pWellData == nullptr) { + if(pWellData == nullptr) { this->createWell(); } } @@ -400,8 +231,7 @@ void nmObjPointWell::setWellData(ZxDataWell *wellObj) { if(wellObj) { m_bSelectWell = true; - m_pWellData = wellObj; - m_sWellID = m_pWellData->getCode(); + m_sWellID = wellObj->getCode(); } } @@ -428,19 +258,18 @@ void nmObjPointWell::createWell() pWellDialog->setActionMode(DAM_Edit); // 初始化UI pWellDialog->initUI(); - // 图元保存井数据 + // 图元保存井ID m_sWellID = pWellData->getCode(); - m_pWellData = pWellData; // 模态展示 if(pWellDialog->exec() == QDialog::Rejected) { - // TODO,如果是 选择的井,则直接删除画布上的图元 - // TODO,如果是 新建的井,删除图元 + 井数据! + // TODO,如果是选择的井,则直接删除画布上的图元 + // TODO,如果是新建的井,删除图元 + 井数据! nmSingalCenter::getInstance()->emitSigDeleteWell(sCode); } else { // 将数据做转换,然后移动到指定的位置 QVector vecPoss; - vecPoss << QPointF(m_pWellData->getLocationX(), m_pWellData->getLocationY()); + vecPoss << QPointF(pWellData->getLocationX(), pWellData->getLocationY()); nmDataLogFile::getInstance()->writeLog(" =========== " + QString::number(vecPoss[0].x()) + " " + QString::number( vecPoss[0].y())); // 将数据做转换,然后移动到指定的位置 @@ -456,84 +285,24 @@ void nmObjPointWell::createWell() void nmObjPointWell::editWell() { - // 如果没有层数据,提示用户定义分层信息 - if(m_pGraphicBinder && !m_pGraphicBinder->hasLayers()) { - QMessageBox::information(nullptr, tr("error"), tr("please setting layers Data!")); - return; - } - - nmPlotDialogContextProvider* pDialogProvider = nmPlotDialogContext::provider(); - if(pDialogProvider == nullptr) { + if (m_pGraphicBinder == nullptr) { return; } - nmDataWellBase* pReturnWellData = nullptr; - - if(pDialogProvider->editWell(nullptr, m_pWellData, m_pNmWellData, pReturnWellData)) { - // 获取修改后的井数据 - if (pReturnWellData == nullptr || m_pWellData == nullptr || m_pNmWellData == nullptr) { - return; - } - - // 更新ZxDataWell的数据 - m_pWellData->setName(pReturnWellData->getWellName()); - this->setName(pReturnWellData->getWellName()); - m_pWellData->setLocationX(pReturnWellData->getX().getValue().toDouble()); - m_pWellData->setLocationY(pReturnWellData->getY().getValue().toDouble()); - m_pWellData->setWellRadius(pReturnWellData->getRadius().getValue().toDouble()); - NM_WELL_MODEL eWellType = pReturnWellData->getWellType(); - - // 修改了井类型,就重新设置 - if (eWellType != m_enumWellType) - { - m_enumWellType = eWellType; - QString sWellClass; - if (m_enumWellType == NM_WELL_MODEL::Vertical_Well) - { - sWellClass = "VerticalWell"; - } else if(m_enumWellType == NM_WELL_MODEL::Vertical_Fractured_Well) { - sWellClass = "VerticalFracturedWell"; - } else if(m_enumWellType == NM_WELL_MODEL::Horizontal_Fractured_Well) { - sWellClass = "HorizontalFracturedWell"; - } - m_pWellData->setWellClassCn(sWellClass); - } + if(m_pGraphicBinder->editWellForGraphic(this, m_enumWellType, m_pNameLabel)) { + ZxDataWell* pWellData = getWellData(); + if (pWellData != nullptr) { + // 根据新坐标进行移动 + QVector vecPoss; + vecPoss << QPointF(pWellData->getLocationX(), pWellData->getLocationY()); - if (m_pNameLabel != nullptr) { - m_pNameLabel->setText(pReturnWellData->getWellName()); + // 将数据做转换,然后移动到指定的位置 + this->setAllPos(vecPoss); + moveToPos(this->getPosOf(this->getAllPos())); } - - // 根据新坐标进行移动 - QVector vecPoss; - vecPoss << QPointF(m_pWellData->getLocationX(), m_pWellData->getLocationY()); - - // 将数据做转换,然后移动到指定的位置 - this->setAllPos(vecPoss); - moveToPos(this->getPosOf(this->getAllPos())); - - // 判断是不是当前查看的井 - nmDataWellBase* pCurWellData = m_pGraphicBinder->getCurrentWellData(); - if (pCurWellData != nullptr && pCurWellData->getWellName() == m_pNmWellData->getWellName()) - { - // 设置到当前井 - m_pGraphicBinder->setCurrentWellData(pReturnWellData); - } - - // 更新当前井数据,并添加到数据中心 - m_pGraphicBinder->removeWellData(m_pNmWellData); - - if (m_pNmWellData != nullptr) - { - m_pNmWellData = nullptr; - } - m_pNmWellData = pReturnWellData; - m_pGraphicBinder->appendWellData(m_pNmWellData); - m_pGraphicBinder->updateWellDataMapping(this, m_pNmWellData); } - if (m_pGraphicBinder) { - m_pGraphicBinder->notifyDataChanged(); - } + m_pGraphicBinder->notifyDataChanged(); this->update(); } @@ -541,11 +310,12 @@ void nmObjPointWell::editWell() QVector nmObjPointWell::getWellInformation() { QVector wellInformation; + ZxDataWell* pWellData = getWellData(); - if(m_pWellData) { - wellInformation.append(m_pWellData->getLocationX()); - wellInformation.append(m_pWellData->getLocationY()); - wellInformation.append(m_pWellData->getWellRadius()); + if(pWellData) { + wellInformation.append(pWellData->getLocationX()); + wellInformation.append(pWellData->getLocationY()); + wellInformation.append(pWellData->getWellRadius()); } return wellInformation; @@ -553,7 +323,10 @@ QVector nmObjPointWell::getWellInformation() ZxDataWell* nmObjPointWell::getWellData() const { - return m_pWellData; + if (zxCurProject == nullptr) { + return nullptr; + } + return dynamic_cast(zxCurProject->getChild(iDataModelType::sTypeWell, m_sWellID)); } const QString& nmObjPointWell::getWellID() const @@ -574,14 +347,19 @@ void nmObjPointWell::paintBack(QPainter* painter, const ZxPaintParam& param) m_pNameLabel->setText(sName); } } - - if (m_pWellData == nullptr) { + + if (m_pGraphicBinder == nullptr) { + return; + } + + nmPlotGraphicBinder::WellRenderData renderData = m_pGraphicBinder->getWellRenderData(this); + if (!renderData.valid) { return; } - QString wellClass = m_pWellData->getWellClassEn(); + m_enumWellType = renderData.wellType; - if(ZxBaseUtil::isSameStr(wellClass, "VerticalFracturedWell") && m_pNmWellData != nullptr) { // 编辑完井之后 + if(renderData.wellType == NM_WELL_MODEL::Vertical_Fractured_Well) { // 编辑完井之后 Q_ASSERT(NULL != m_pAxisX); Q_ASSERT(NULL != m_pAxisY); @@ -592,31 +370,13 @@ void nmObjPointWell::paintBack(QPainter* painter, const ZxPaintParam& param) painter->save(); - double locX = m_pNmWellData->getX().getValue().toDouble(); - double locY = m_pNmWellData->getY().getValue().toDouble(); - double rad = m_pNmWellData->getRadius().getValue().toDouble(); - - m_vecPoints[0].setX(locX); - m_vecPoints[0].setY(locY); - - m_pWellData->setLocationX(locX); - m_pWellData->setLocationY(locY); - m_pWellData->setWellRadius(rad); - - double x = m_pWellData->getLocationX(); - double y = m_pWellData->getLocationY(); - QPointF point(x, y); + QPointF point(renderData.x, renderData.y); + m_vecPoints[0] = point; QPointF ptPos = getPosOf(point); moveToPos(this->getPosOf(m_vecPoints)); - nmDataVerticalFracturedWell* pVFWell = dynamic_cast(m_pNmWellData); - if (pVFWell == nullptr) { - painter->restore(); - return; - } - // 绘制填充 double r = m_oDot.radius(); @@ -642,16 +402,15 @@ void nmObjPointWell::paintBack(QPainter* painter, const ZxPaintParam& param) painter->setPen(fracturePen); // 绘制裂缝 - QVector vecFracs = pVFWell->getFracs(); - if (vecFracs.size() == 2) { - QPointF startPos = getPosOf(vecFracs[0]); - QPointF endPos_frac = getPosOf(vecFracs[1]); + if (renderData.verticalFracs.size() == 2) { + QPointF startPos = getPosOf(renderData.verticalFracs[0]); + QPointF endPos_frac = getPosOf(renderData.verticalFracs[1]); painter->drawLine(startPos, endPos_frac); } painter->restore(); - } else if(ZxBaseUtil::isSameStr(wellClass, "HorizontalFracturedWell") && m_pNmWellData != nullptr) { + } else if(renderData.wellType == NM_WELL_MODEL::Horizontal_Fractured_Well) { Q_ASSERT(NULL != m_pAxisX); Q_ASSERT(NULL != m_pAxisY); @@ -662,45 +421,27 @@ void nmObjPointWell::paintBack(QPainter* painter, const ZxPaintParam& param) painter->save(); - double locX = m_pNmWellData->getX().getValue().toDouble(); - double locY = m_pNmWellData->getY().getValue().toDouble(); - double rad = m_pNmWellData->getRadius().getValue().toDouble(); - - m_vecPoints[0].setX(locX); - m_vecPoints[0].setY(locY); - - m_pWellData->setLocationX(locX); - m_pWellData->setLocationY(locY); - m_pWellData->setWellRadius(rad); - - double x = m_pWellData->getLocationX(); - double y = m_pWellData->getLocationY(); - QPointF point(x, y); + QPointF point(renderData.x, renderData.y); + m_vecPoints[0] = point; QPointF ptPos = getPosOf(point); moveToPos(this->getPosOf(m_vecPoints)); - nmDataHorizontalFracturedWell* pHFWell = dynamic_cast(m_pNmWellData); - if (pHFWell == nullptr) { - painter->restore(); - return; - } - // 获取井长 - double wellLength = pHFWell->getWellLength().getValue().toDouble(); + double wellLength = renderData.wellLength; // 获取井的角度 - double drainAngle = pHFWell->getDrainAngle().getValue().toDouble(); + double drainAngle = renderData.drainAngle; // 将角度从度转换为弧度 - double angleRad = drainAngle * M_PI / 180.0; // M_PI 是 π 的值,表示 180 度 + double angleRad = drainAngle * M_PI / 180.0; // M_PI 是π的值,表示 180 度 // 获取裂缝角度(单位:度) //double fractureAngle = m_HFracturedWell->getFractureAngle().getValue().toDouble(); //double fractureAngleRad = fractureAngle * M_PI / 180.0; // 转换为弧度 // 计算井的终点坐标 - double endX = x + wellLength * cos(angleRad); - double endY = y + wellLength * sin(angleRad); + double endX = renderData.x + wellLength * cos(angleRad); + double endY = renderData.y + wellLength * sin(angleRad); QPointF endPoint(endX, endY); QPointF endPos = getPosOf(endPoint); @@ -730,16 +471,14 @@ void nmObjPointWell::paintBack(QPainter* painter, const ZxPaintParam& param) // 井筒 painter->drawLine(ptPos, endPos); - // 获取预先计算好的裂缝坐标 - QVector>& vecFracs = pHFWell->getFracs(); - // 设置裂缝的画笔 QPen fracturePen(QColor(255, 0, 0)); fracturePen.setWidth(0.3f); painter->setPen(fracturePen); // 遍历并绘制所有裂缝 - foreach (const auto& frac , vecFracs) { + for(int i = 0; i < renderData.horizontalFracs.size(); ++i) { + const QPair& frac = renderData.horizontalFracs.at(i); // 将世界坐标转换为绘图坐标 QPointF startPos = getPosOf(frac.first); QPointF endPos_frac = getPosOf(frac.second); @@ -750,20 +489,8 @@ void nmObjPointWell::paintBack(QPainter* painter, const ZxPaintParam& param) painter->restore(); } else { //其他 - if(m_pNmWellData != nullptr) { - double locX = m_pNmWellData->getX().getValue().toDouble(); - double locY = m_pNmWellData->getY().getValue().toDouble(); - double rad = m_pNmWellData->getRadius().getValue().toDouble(); - - m_vecPoints[0].setX(locX); - m_vecPoints[0].setY(locY); - - m_pWellData->setLocationX(locX); - m_pWellData->setLocationY(locY); - m_pWellData->setWellRadius(rad); - - moveToPos(this->getPosOf(m_vecPoints)); - } + m_vecPoints[0] = QPointF(renderData.x, renderData.y); + moveToPos(this->getPosOf(m_vecPoints)); nmObjPoint::paintBack(painter, param); } @@ -774,39 +501,17 @@ void nmObjPointWell::removeData() if (m_pGraphicBinder) { m_pGraphicBinder->removeWellBinding(this); } - m_pNmWellData = nullptr; } -void nmObjPointWell::setNmWellData(nmDataWellBase* wellData) +void nmObjPointWell::markWellDataBound(NM_WELL_MODEL wellType) { - // 如果是外界设置了当前图元绑定的井数据,则不需要再次在afterCreated()函数中再次设置数据 m_bSelectWell = false; - m_pNmWellData = wellData; - - if (m_pWellData) { - QString wellClass = m_pWellData->getWellClassEn(); - - if(ZxBaseUtil::isSameStr(wellClass, "VerticalWell")) { - m_enumWellType = NM_WELL_MODEL::Vertical_Well; - } else if(ZxBaseUtil::isSameStr(wellClass, "VerticalFracturedWell")) { - m_enumWellType = NM_WELL_MODEL::Vertical_Fractured_Well; - } else if(ZxBaseUtil::isSameStr(wellClass, "HorizontalFracturedWell")) { - m_enumWellType = NM_WELL_MODEL::Horizontal_Fractured_Well; - } - } -} - -nmDataWellBase* nmObjPointWell::getNmWellData() -{ - return m_pNmWellData; + m_enumWellType = wellType; } void nmObjPointWell::onObjVisibleChanged(bool bIsVisible) { if (m_pGraphicBinder) { - nmDataWellBase* pData = m_pGraphicBinder->getWellDataFor(this); - if (pData) { - pData->setPlotVisible(bIsVisible); - } + m_pGraphicBinder->setWellVisible(this, bIsVisible); } } diff --git a/Src/nmNum/nmPlot/nmPlotGraphicBinder.cpp b/Src/nmNum/nmPlot/nmPlotGraphicBinder.cpp index 213f17b..8a6d708 100644 --- a/Src/nmNum/nmPlot/nmPlotGraphicBinder.cpp +++ b/Src/nmNum/nmPlot/nmPlotGraphicBinder.cpp @@ -18,9 +18,32 @@ #include "nmDataAnalyzeManager.h" #include "nmObjPointWell.h" #include "nmDataWellBase.h" +#include "nmDataVerticalFracturedWell.h" +#include "nmDataHorizontalFracturedWell.h" +#include "nmPlotDialogContext.h" +#include "nmPlotDialogContextProvider.h" +#include "ZxDataWell.h" +#include "ZxObjText.h" +#include "ZxDataGaugeP.h" +#include "ZxDataGaugeF.h" +#include "ZxBaseUtil.h" +#include "Defines.h" +#include "iDataTypes.h" +#include "zxSysUtils.h" #include +#include +nmPlotGraphicBinder::WellRenderData::WellRenderData() + : valid(false) + , wellType(Vertical_Well) + , x(0.0) + , y(0.0) + , radius(0.0) + , wellLength(0.0) + , drainAngle(0.0) +{ +} nmPlotGraphicBinder::nmPlotGraphicBinder(nmDataAnalyzeManager* pDataMgr, QObject* parent) : QObject(parent) , m_pDataMgr(pDataMgr) @@ -1324,8 +1347,10 @@ nmDataWellBase* nmPlotGraphicBinder::createWellForGraphic(nmObjPointWell* pGraph nmDataWellBase* pData = m_pDataMgr->createWell(wellType); + // 建立图元到数值井数据的映射,图元后续只通过Binder访问井数据。 m_mapWellData[pGraphic] = pData; pGraphic->setGraphicBinder(this); + pGraphic->markWellDataBound(wellType); _connectWell(pGraphic, pData); @@ -1371,6 +1396,7 @@ void nmPlotGraphicBinder::syncWellData(nmObjPointWell* pGraphic) nmDataWellBase* pData = m_mapWellData.value(pGraphic, nullptr); if (!pData) return; + ZxDataWell* pWellData = pGraphic->getWellData(); // 同步名称(用户在属性面板改名后,同步到数据中心和框架数据) QString sName = pGraphic->getName(); @@ -1378,13 +1404,19 @@ void nmPlotGraphicBinder::syncWellData(nmObjPointWell* pGraphic) if (pData->getWellName() != sName) { pData->setWellName(sName); } - ZxDataWell* pWellData = pGraphic->getWellData(); if (pWellData && pWellData->getName() != sName) { pWellData->setName(sName); pWellData->save(); } } + if (pWellData) { + // 数值井数据是分析侧的数据源,这里回写到框架井数据,保证保存工程树时一致。 + pWellData->setLocationX(pData->getX().getValue().toDouble()); + pWellData->setLocationY(pData->getY().getValue().toDouble()); + pWellData->setWellRadius(pData->getRadius().getValue().toDouble()); + } + // 同步图元外观属性到井数据(用于保存到 JSON) ZxDot dot = pGraphic->getDot(); pData->setDotStyle(static_cast(dot.style())); @@ -1401,6 +1433,272 @@ nmDataWellBase* nmPlotGraphicBinder::getWellDataFor(nmObjPointWell* pGraphic) return m_mapWellData.value(pGraphic, nullptr); } +bool nmPlotGraphicBinder::hasWellDataFor(nmObjPointWell* pGraphic) const +{ + return m_mapWellData.value(pGraphic, nullptr) != nullptr; +} + +bool nmPlotGraphicBinder::isCurrentWellGraphic(nmObjPointWell* pGraphic) const +{ + if (!m_pDataMgr || !pGraphic) return false; + return m_mapWellData.value(pGraphic, nullptr) == m_pDataMgr->getCurWellData(); +} + +void nmPlotGraphicBinder::syncWellMoveFromGraphic(nmObjPointWell* pGraphic, + NM_WELL_MODEL wellType, + const QPointF& newLocation) +{ + if (!pGraphic) return; + ZxDataWell* pWellData = pGraphic->getWellData(); + if (!pWellData) return; + + nmDataWellBase* pData = m_mapWellData.value(pGraphic, nullptr); + if (!pData) return; + + // 图元拖动先更新框架井数据,再同步到数值井数据。 + pWellData->setLocationX(newLocation.x()); + pWellData->setLocationY(newLocation.y()); + + nmDataAttribute tempAttr = pData->getX(); + tempAttr.setValue(pWellData->getLocationX()); + pData->setX(tempAttr); + tempAttr = pData->getY(); + tempAttr.setValue(pWellData->getLocationY()); + pData->setY(tempAttr); + tempAttr = pData->getRadius(); + tempAttr.setValue(pWellData->getWellRadius()); + pData->setRadius(tempAttr); + + if (wellType == NM_WELL_MODEL::Vertical_Fractured_Well) { + // 裂缝井位置变化后,裂缝端点需要跟着重新计算。 + if (nmDataVerticalFracturedWell* pVFWell = dynamic_cast(pData)) { + pVFWell->setFracs(); + } + } else if (wellType == NM_WELL_MODEL::Horizontal_Fractured_Well) { + // 水平裂缝井同样依赖井筒位置重新计算裂缝几何。 + if (nmDataHorizontalFracturedWell* pHFWell = dynamic_cast(pData)) { + pHFWell->setFracs(); + } + } +} + +bool nmPlotGraphicBinder::ensureSelectedWellData(nmObjPointWell* pGraphic, + NM_WELL_MODEL& wellType) +{ + if (!pGraphic) return false; + ZxDataWell* pWellData = pGraphic->getWellData(); + if (!pWellData) return false; + + nmDataWellBase* pData = m_mapWellData.value(pGraphic, nullptr); + if (pData != nullptr) { + // 已经绑定过的图元直接复用数据,避免重复创建数值井对象。 + wellType = pData->getWellType(); + return true; + } + + // 选择井来自工程树,需要先把工程井类型转换成数值井类型。 + QString wellClass = pWellData->getWellClassEn(); + if(ZxBaseUtil::isSameStr(wellClass, "VerticalWell")) { + wellType = NM_WELL_MODEL::Vertical_Well; + } else if(ZxBaseUtil::isSameStr(wellClass, "VerticalFracturedWell")) { + wellType = NM_WELL_MODEL::Vertical_Fractured_Well; + } else if(ZxBaseUtil::isSameStr(wellClass, "HorizontalFracturedWell")) { + wellType = NM_WELL_MODEL::Horizontal_Fractured_Well; + } else { + return false; + } + + pData = createWellForGraphic(pGraphic, wellType); + if (pData == nullptr) { + return false; + } + + // 重新勾选井时在这里补建nmDataWell,并将工程树中的基础属性同步进去。 + pData->setWellName(pWellData->getName()); + nmDataAttribute tempAttr = pData->getX(); + tempAttr.setValue(pWellData->getLocationX()); + pData->setX(tempAttr); + tempAttr = pData->getY(); + tempAttr.setValue(pWellData->getLocationY()); + pData->setY(tempAttr); + tempAttr = pData->getRadius(); + tempAttr.setValue(pWellData->getWellRadius()); + pData->setRadius(tempAttr); + + ZxDataObjectList listGaugeP = pWellData->getChildren(iDataModelType::sTypeDataGaugeP); + ZxDataObjectList listGaugeF = pWellData->getChildren(iDataModelType::sTypeDataGaugeF); + ZxDataGaugeP* pGaugeP = nullptr; + ZxDataGaugeF* pGaugeF = nullptr; + + // 从工程树井节点下取第一条压力/流量数据,转换成数值井需要的曲线点。 + for(int i = 0; i < listGaugeP.size(); ++i) { + if(pGaugeP = dynamic_cast(listGaugeP[i])) { + break; + } + } + + for(int i = 0; i < listGaugeF.size(); ++i) { + if(pGaugeF = dynamic_cast(listGaugeF[i])) { + break; + } + } + + QVector pressurePoints, flowPoints; + VecDouble vecX, vecY; + if(pGaugeP != nullptr && pGaugeP->getDataVecXY(vecX, vecY)) { + for(int i = 0; i < vecX.size(); ++i) { + if(i < vecY.size()) { + pressurePoints.append(QPointF(vecX[i], vecY[i])); + } + } + } + + vecX.clear(); + vecY.clear(); + if(pGaugeF != nullptr && pGaugeF->getDataVecXY(vecX, vecY)) { + for(int i = 0; i < vecX.size(); ++i) { + if(i < vecY.size()) { + flowPoints.append(QPointF(vecX[i], vecY[i])); + } + } + } + + int indexF = -2; + if(pWellData != zxCurWell) { + // 非当前查看井默认使用最后一段流量段。 + indexF = flowPoints.count() - 1; + } + + pData->setPressurePoints(pressurePoints); + pData->setFlowPoints(flowPoints); + + if(indexF >= -1) { + pData->setIndexF(indexF); + } + + if (wellType == NM_WELL_MODEL::Vertical_Fractured_Well) { + if (nmDataVerticalFracturedWell* pVFWell = dynamic_cast(pData)) { + pVFWell->setFracs(); + } + } else if (wellType == NM_WELL_MODEL::Horizontal_Fractured_Well) { + if (nmDataHorizontalFracturedWell* pHFWell = dynamic_cast(pData)) { + pHFWell->setFracs(); + } + } + + QVector> vvecHistoryPressureData; + QVector> vvecHistoryLogData; + QVector> vvecHistorySemiLogData; + // 初始化历史压力、双对数和半对数数据,保证重新显示后可直接分析。 + calculateWellLogData(pData, vvecHistoryPressureData, vvecHistoryLogData, vvecHistorySemiLogData); + pData->setHistoryPressure(vvecHistoryPressureData); + pData->setHistoryLogLog(vvecHistoryLogData); + pData->setHistorySemiLog(vvecHistorySemiLogData); + return true; +} + +bool nmPlotGraphicBinder::editWellForGraphic(nmObjPointWell* pGraphic, + NM_WELL_MODEL& wellType, + ZxObjText* pNameLabel) +{ + if (!pGraphic) return false; + ZxDataWell* pWellData = pGraphic->getWellData(); + if (!pWellData) return false; + if(!hasLayers()) { + QMessageBox::information(nullptr, tr("error"), tr("please setting layers Data!")); + return false; + } + + nmPlotDialogContextProvider* pDialogProvider = nmPlotDialogContext::provider(); + if(pDialogProvider == nullptr) { + return false; + } + + nmDataWellBase* pOldData = m_mapWellData.value(pGraphic, nullptr); + nmDataWellBase* pReturnWellData = nullptr; + + // 编辑弹窗同时依赖框架井数据和数值井数据,由Binder集中传入,图元不持有数据指针。 + if(!pDialogProvider->editWell(nullptr, pWellData, pOldData, pReturnWellData)) { + return false; + } + + if (pReturnWellData == nullptr || pOldData == nullptr) { + return false; + } + + pWellData->setName(pReturnWellData->getWellName()); + pGraphic->setName(pReturnWellData->getWellName()); + pWellData->setLocationX(pReturnWellData->getX().getValue().toDouble()); + pWellData->setLocationY(pReturnWellData->getY().getValue().toDouble()); + pWellData->setWellRadius(pReturnWellData->getRadius().getValue().toDouble()); + NM_WELL_MODEL eWellType = pReturnWellData->getWellType(); + + if (eWellType != wellType) { + wellType = eWellType; + QString sWellClass; + if (wellType == NM_WELL_MODEL::Vertical_Well) { + sWellClass = "VerticalWell"; + } else if(wellType == NM_WELL_MODEL::Vertical_Fractured_Well) { + sWellClass = "VerticalFracturedWell"; + } else if(wellType == NM_WELL_MODEL::Horizontal_Fractured_Well) { + sWellClass = "HorizontalFracturedWell"; + } + pWellData->setWellClassCn(sWellClass); + } + + if (pNameLabel != nullptr) { + pNameLabel->setText(pReturnWellData->getWellName()); + } + + nmDataWellBase* pCurWellData = getCurrentWellData(); + if (pCurWellData != nullptr && pCurWellData->getWellName() == pOldData->getWellName()) { + // 如果编辑的是当前分析井,需要同步替换DataManager中的当前井指针。 + setCurrentWellData(pReturnWellData); + } + + // 编辑返回的是新的数值井数据对象,旧对象移除后重建映射。 + removeWellData(pOldData); + appendWellData(pReturnWellData); + updateWellDataMapping(pGraphic, pReturnWellData); + return true; +} + +nmPlotGraphicBinder::WellRenderData nmPlotGraphicBinder::getWellRenderData(nmObjPointWell* pGraphic) const +{ + WellRenderData renderData; + nmDataWellBase* pData = m_mapWellData.value(pGraphic, nullptr); + if (!pData) { + return renderData; + } + + // 图元绘制阶段只读取快照,不直接持有nmDataWell指针。 + renderData.valid = true; + renderData.wellType = pData->getWellType(); + renderData.x = pData->getX().getValue().toDouble(); + renderData.y = pData->getY().getValue().toDouble(); + renderData.radius = pData->getRadius().getValue().toDouble(); + + if (nmDataVerticalFracturedWell* pVFWell = dynamic_cast(pData)) { + // 裂缝几何由数据对象预先计算,图元只负责坐标转换和绘制。 + renderData.verticalFracs = pVFWell->getFracs(); + } else if (nmDataHorizontalFracturedWell* pHFWell = dynamic_cast(pData)) { + // 水平井绘制需要井长、角度和多段裂缝几何。 + renderData.wellLength = pHFWell->getWellLength().getValue().toDouble(); + renderData.drainAngle = pHFWell->getDrainAngle().getValue().toDouble(); + renderData.horizontalFracs = pHFWell->getFracs(); + } + + return renderData; +} + +void nmPlotGraphicBinder::setWellVisible(nmObjPointWell* pGraphic, bool bVisible) +{ + nmDataWellBase* pData = m_mapWellData.value(pGraphic, nullptr); + if (pData) { + pData->setPlotVisible(bVisible); + } +} + void nmPlotGraphicBinder::calculateWellLogData(nmDataWellBase* pWellData, QVector>& pressure, QVector>& logLog, @@ -1471,7 +1769,7 @@ void nmPlotGraphicBinder::_pushWellDataToGraphic(nmObjPointWell* pGraphic, nmDat pGraphic->blockSignals(true); - pGraphic->setNmWellData(pData); + pGraphic->markWellDataBound(pData->getWellType()); // 从井数据恢复图元外观属性(加载时从 JSON 恢复的属性设置到图元) ZxDot dot = pGraphic->getDot(); diff --git a/Src/nmNum/nmSubWnd/nmSubWndMain.cpp b/Src/nmNum/nmSubWnd/nmSubWndMain.cpp index 3f70a8f..a0d3377 100644 --- a/Src/nmNum/nmSubWnd/nmSubWndMain.cpp +++ b/Src/nmNum/nmSubWnd/nmSubWndMain.cpp @@ -1020,7 +1020,7 @@ void nmSubWndMain::updateSelectedWells(QList wellObjList) for(int i = 0; i < vDeleteWellPlotList.count(); ++i) { nmObjPointWell* pWellPlot = vDeleteWellPlotList[i]; // 如果是当前井,不可删除 (保留您的逻辑) - if(pWellPlot->getNmWellData() == nmDataAnalyzeManager::getCurrentInstance()->getCurWellData()) + if(m_pWxPlot->graphicBinder() && m_pWxPlot->graphicBinder()->isCurrentWellGraphic(pWellPlot)) continue; // 删除对应的参数类 @@ -1043,6 +1043,10 @@ void nmSubWndMain::updateSelectedWells(QList wellObjList) if(pWellPlot == NULL) { continue; } + // 选择已有井重新生成图元时,先恢复Binder,后续afterCreated才能建立井数据绑定 + if(m_pWxPlot->graphicBinder()) { + pWellPlot->setGraphicBinder(m_pWxPlot->graphicBinder()); + } // 设置图元的井数据 pWellPlot->setWellData(wellObj); // 移动到正确的位置