diff --git a/Include/nmNum/nmData/nmDataOutline.h b/Include/nmNum/nmData/nmDataOutline.h index 0f7d7c2..718d664 100644 --- a/Include/nmNum/nmData/nmDataOutline.h +++ b/Include/nmNum/nmData/nmDataOutline.h @@ -3,6 +3,8 @@ #include "nmData_global.h" +#include + #include "nmDefines.h" #include "nmDataBase.h" @@ -42,6 +44,18 @@ class NM_DATA_EXPORT nmDataOutline : public nmDataBase { bool getPlotVisible() const; void setPlotVisible(const bool newState); + // 视觉属性(画笔宽度、填充色、透明度) + double getPenWidth() const; + void setPenWidth(double dWidth); + QColor getBackgrdColor() const; + void setBackgrdColor(const QColor& clr); + int getBackgrdAlpha() const; + void setBackgrdAlpha(int nAlpha); + + // 视觉属性是否有效(仅从已保存文件加载后为true,新建时为false) + bool hasVisualProps() const; + void setVisualPropsValid(bool bValid); + private: QString m_sName;// 边界名称 QVector m_vecPts; // 边界点的数据; @@ -54,6 +68,12 @@ class NM_DATA_EXPORT nmDataOutline : public nmDataBase { double m_dRadius; // 半径 bool m_bPlotVisible; // 图元是否可见 + + // 视觉属性 + double m_dPenWidth; // 画笔宽度 + QColor m_clrBackgrd; // 填充背景色 + int m_nBackgrdAlpha; // 填充透明度 (0-255) + bool m_bHasVisualProps; // 视觉属性是否有效(从文件加载后为true) }; #endif // NMDATARECTOUTLINE_H diff --git a/Include/nmNum/nmPlot/nmObjPolygonOutline.h b/Include/nmNum/nmPlot/nmObjPolygonOutline.h index e53e3d8..794d9e7 100644 --- a/Include/nmNum/nmPlot/nmObjPolygonOutline.h +++ b/Include/nmNum/nmPlot/nmObjPolygonOutline.h @@ -4,7 +4,7 @@ #include "nmDefines.h" #include "nmPlot_global.h" -#include "nmDataOutline.h" +class nmPlotGraphicBinder; // 数值试井绘图对象(多边形) class NM_PLOT_EXPORT nmObjPolygonOutline : public nmObjPolygon @@ -71,20 +71,23 @@ public: virtual void afterCreated() override; // 删除多边形边界数据对象 - virtual void removeData() override; + virtual void removeData() override; // 当前选中边界的类型 void setCurOutlineFlowType(int); int getCurOutlineFlowType(); - nmDataOutline* getOutlineData() const; - void setOutlineData(nmDataOutline* newOutlineData); + // 注入 Binder 指针 + void setGraphicBinder(nmPlotGraphicBinder* pBinder) { m_pGraphicBinder = pBinder; } + +signals: + // 点坐标变更 + void sigOutlinePointsChanged(); + // 流动类型变更 + void sigOutlineFlowTypeChanged(); - public slots: - // 图元状态改变 - void onObjVisibleChanged(bool bIsVisible); public: QVector m_vFlowTypeList; // 边界的压力类型 - nmDataOutline* m_outlineData; // 边界数据 + nmPlotGraphicBinder* m_pGraphicBinder; }; diff --git a/Include/nmNum/nmPlot/nmObjRectOutline.h b/Include/nmNum/nmPlot/nmObjRectOutline.h index 82bb88c..587201d 100644 --- a/Include/nmNum/nmPlot/nmObjRectOutline.h +++ b/Include/nmNum/nmPlot/nmObjRectOutline.h @@ -4,7 +4,7 @@ #include "nmDefines.h" #include "nmPlot_global.h" -#include "nmDataOutline.h" +class nmPlotGraphicBinder; // 数值试井绘图对象(矩形) class NM_PLOT_EXPORT nmObjRectOutline : public nmObjRect @@ -64,9 +64,6 @@ public: // 删除矩形边界数据对象 virtual void removeData() override; - nmDataOutline* getOutlineData() const; - void setOutlineData(nmDataOutline* newOutlineData); - // 新增方法,按照绘图坐标系更新矩形边界四个点的顺序为【左上角、右上角、右下角、左下角】顺时针排布 void reorderPoints(QVector& points); @@ -86,13 +83,18 @@ public: void setLeftOutlineFlowType(int newValue); int getLeftOutlineFlowType(); - public slots: - // 图元状态改变 - void onObjVisibleChanged(bool bIsVisible); + // 注入 Binder 指针 + void setGraphicBinder(nmPlotGraphicBinder* pBinder) { m_pGraphicBinder = pBinder; } + +signals: + // 点坐标变更 + void sigOutlinePointsChanged(); + // 流动类型变更 + void sigOutlineFlowTypeChanged(); public: QVector m_vFlowTypeList; // 边界的压力类型 RectBoundPos m_eChangeOutlineType; // 需要修改哪个边界的压力类型 - nmDataOutline* m_outlineData; // 边界数据 + nmPlotGraphicBinder* m_pGraphicBinder; }; diff --git a/Include/nmNum/nmPlot/nmObjRoundOutline.h b/Include/nmNum/nmPlot/nmObjRoundOutline.h index 7dc0559..3ca5f3f 100644 --- a/Include/nmNum/nmPlot/nmObjRoundOutline.h +++ b/Include/nmNum/nmPlot/nmObjRoundOutline.h @@ -4,7 +4,7 @@ #include "nmDefines.h" #include "nmPlot_global.h" -#include "nmDataOutline.h" +class nmPlotGraphicBinder; // 数值试井绘图对象(圆形) class NM_PLOT_EXPORT nmObjRoundOutline : public nmObjRound @@ -59,16 +59,18 @@ public: void setCurOutlineFlowType(int); int getCurOutlineFlowType(); - nmDataOutline* getOutlineData() const; - void setOutlineData(nmDataOutline* newOutlineData); + // 注入 Binder 指针 + void setGraphicBinder(nmPlotGraphicBinder* pBinder) { m_pGraphicBinder = pBinder; } - public slots: - // 图元状态改变 - void onObjVisibleChanged(bool bIsVisible); +signals: + // 点坐标变更 + void sigOutlinePointsChanged(); + // 流动类型变更 + void sigOutlineFlowTypeChanged(); public: // 边界的压力类型 QVector m_vFlowTypeList; - nmDataOutline* m_outlineData; // 边界数据 + nmPlotGraphicBinder* m_pGraphicBinder; }; diff --git a/Include/nmNum/nmPlot/nmPlotGraphicBinder.h b/Include/nmNum/nmPlot/nmPlotGraphicBinder.h index 8ee9960..715e1a8 100644 --- a/Include/nmNum/nmPlot/nmPlotGraphicBinder.h +++ b/Include/nmNum/nmPlot/nmPlotGraphicBinder.h @@ -11,6 +11,11 @@ class nmDataFault; class nmObjLineFault; class nmDataFracture; class nmObjLineCrack; +class nmDataOutline; +class nmObjBase; +class nmObjRoundOutline; +class nmObjRectOutline; +class nmObjPolygonOutline; // 图元与数据绑定协调器,由 nmGuiPlot 托管 class NM_PLOT_EXPORT nmPlotGraphicBinder : public QObject @@ -50,6 +55,30 @@ public: // 名称同步,由图元在 paintBack 中调用 void syncCrackName(nmObjLineCrack* pGraphic); + // 调用:用户画完圆形边界后 + void createOutlineForGraphic(nmObjRoundOutline* pGraphic); + + // 调用:用户画完矩形边界后 + void createOutlineForGraphic(nmObjRectOutline* pGraphic); + + // 调用:用户画完多边形边界后 + void createOutlineForGraphic(nmObjPolygonOutline* pGraphic); + + // 调用:从文件加载,绑定已有边界数据到已有图元(三种类型通用) + void bindOutlineToGraphic(nmObjBase* pGraphic, nmDataOutline* pData); + + // 调用:删除边界图元前(三种类型通用) + void removeOutlineBinding(nmObjBase* pGraphic); + + // 查找边界图元对应的数据指针 + nmDataOutline* getOutlineDataFor(nmObjBase* pGraphic); + + // 名称同步,由边界图元在 paintBack 中调用 + void syncOutlineName(nmObjBase* pGraphic); + + // 视觉属性兜底同步(画笔宽度、填充色、透明度),由边界图元在 paintBack 中调用 + void syncOutlineVisual(nmObjBase* pGraphic); + // 切换分析时更新绑定的 DataManager,并清理旧图元的残留映射 void updateDataMgr(nmDataAnalyzeManager* pDataMgr); @@ -71,6 +100,11 @@ private slots: void onGraphicCrackPointsChanged(); void onGraphicCrackVisibleChanged(bool bVisible); + // 边界图元信号 → 数据同步 + void onGraphicOutlinePointsChanged(); + void onGraphicOutlineFlowTypeChanged(); + void onGraphicOutlineVisibleChanged(bool bVisible); + private: nmDataAnalyzeManager* m_pDataMgr; // 数据中心,不持有,外部注入 @@ -103,4 +137,19 @@ private: // 从裂缝数据对象读取值,写入图元本地副本(加载时用) void _pushCrackDataToGraphic(nmObjLineCrack* pGraphic, nmDataFracture* pData); + + // 边界图元 → 数据 的映射表(三种边界类型共用) + QMap m_mapOutlineData; + + // 已建立信号连接的边界图元集合 + QSet m_setBoundOutlineGraphics; + + // 边界图元 ←→ 数据 信号连接(三条信号) + void _connectOutline(nmObjBase* pGraphic, nmDataOutline* pData); + + // 断开指定边界图元与本 Binder 的信号连接 + void _disconnectOutline(nmObjBase* pGraphic); + + // 从边界数据对象读取值,写入图元本地副本(加载时用) + void _pushOutlineDataToGraphic(nmObjBase* pGraphic, nmDataOutline* pData); }; diff --git a/Src/nmNum/nmData/nmDataOutline.cpp b/Src/nmNum/nmData/nmDataOutline.cpp index af2d4cf..f6cfbed 100644 --- a/Src/nmNum/nmData/nmDataOutline.cpp +++ b/Src/nmNum/nmData/nmDataOutline.cpp @@ -10,8 +10,11 @@ nmDataOutline::nmDataOutline() , m_ptCenter() , m_dRadius(0.0) , m_bPlotVisible(true) + , m_dPenWidth(0.0) + , m_clrBackgrd(QColor(0, 0, 255)) + , m_nBackgrdAlpha(0) + , m_bHasVisualProps(false) { - // 图元可见性,默认为true } nmDataOutline::nmDataOutline(const nmDataOutline& other) { @@ -28,6 +31,11 @@ nmDataOutline& nmDataOutline::operator=(const nmDataOutline& other) { m_sName = other.m_sName; m_bPlotVisible = other.m_bPlotVisible; + + m_dPenWidth = other.m_dPenWidth; + m_clrBackgrd = other.m_clrBackgrd; + m_nBackgrdAlpha = other.m_nBackgrdAlpha; + m_bHasVisualProps = other.m_bHasVisualProps; } return *this; } @@ -80,6 +88,13 @@ rapidjson::Value nmDataOutline::ToJsonValue(rapidjson::Document::AllocatorType& // 序列化图元可见性 (m_bPlotVisible) outlineObject.AddMember("PlotVisible", m_bPlotVisible, allocator); // 使用m_bPlotVisible + // 序列化视觉属性 + outlineObject.AddMember("PenWidth", m_dPenWidth, allocator); + outlineObject.AddMember("BackgrdR", m_clrBackgrd.red(), allocator); + outlineObject.AddMember("BackgrdG", m_clrBackgrd.green(), allocator); + outlineObject.AddMember("BackgrdB", m_clrBackgrd.blue(), allocator); + outlineObject.AddMember("BackgrdAlpha", m_nBackgrdAlpha, allocator); + return outlineObject; // 返回序列化后的 RapidJSON Value } @@ -87,8 +102,8 @@ rapidjson::Value nmDataOutline::ToJsonValue(rapidjson::Document::AllocatorType& void nmDataOutline::FromJsonValue(const rapidjson::Value& jsonValue) { // 名称 - if (jsonValue.HasMember("Name") && jsonValue["Name"].IsString()) { - m_sName = QString::fromUtf8(jsonValue["Name"].GetString()); + if (jsonValue.HasMember("OutlineName") && jsonValue["OutlineName"].IsString()) { + m_sName = QString::fromUtf8(jsonValue["OutlineName"].GetString()); } // 反序列化点 @@ -138,6 +153,23 @@ void nmDataOutline::FromJsonValue(const rapidjson::Value& jsonValue) if (jsonValue.HasMember("PlotVisible") && jsonValue["PlotVisible"].IsBool()) { m_bPlotVisible = jsonValue["PlotVisible"].GetBool(); // 使用m_bPlotVisible } + + // 反序列化视觉属性 + bool bHasVisual = false; + if (jsonValue.HasMember("PenWidth") && jsonValue["PenWidth"].IsNumber()) { + m_dPenWidth = jsonValue["PenWidth"].GetDouble(); + bHasVisual = true; + } + int r = 0, g = 0, b = 255; + if (jsonValue.HasMember("BackgrdR") && jsonValue["BackgrdR"].IsInt()) r = jsonValue["BackgrdR"].GetInt(); + if (jsonValue.HasMember("BackgrdG") && jsonValue["BackgrdG"].IsInt()) g = jsonValue["BackgrdG"].GetInt(); + if (jsonValue.HasMember("BackgrdB") && jsonValue["BackgrdB"].IsInt()) b = jsonValue["BackgrdB"].GetInt(); + m_clrBackgrd = QColor(r, g, b); + if (jsonValue.HasMember("BackgrdAlpha") && jsonValue["BackgrdAlpha"].IsInt()) { + m_nBackgrdAlpha = jsonValue["BackgrdAlpha"].GetInt(); + bHasVisual = true; + } + m_bHasVisualProps = bHasVisual; } // Getter and Setter for m_sName @@ -209,3 +241,30 @@ bool nmDataOutline::getPlotVisible() const{ void nmDataOutline::setPlotVisible(const bool newState) { m_bPlotVisible = newState; } + +// 视觉属性 getter/setter +double nmDataOutline::getPenWidth() const { + return m_dPenWidth; +} +void nmDataOutline::setPenWidth(double dWidth) { + m_dPenWidth = dWidth; +} +QColor nmDataOutline::getBackgrdColor() const { + return m_clrBackgrd; +} +void nmDataOutline::setBackgrdColor(const QColor& clr) { + m_clrBackgrd = clr; +} +int nmDataOutline::getBackgrdAlpha() const { + return m_nBackgrdAlpha; +} +void nmDataOutline::setBackgrdAlpha(int nAlpha) { + m_nBackgrdAlpha = nAlpha; +} + +bool nmDataOutline::hasVisualProps() const { + return m_bHasVisualProps; +} +void nmDataOutline::setVisualPropsValid(bool bValid) { + m_bHasVisualProps = bValid; +} diff --git a/Src/nmNum/nmPlot/nmGuiPlot.cpp b/Src/nmNum/nmPlot/nmGuiPlot.cpp index 022d5c0..7fc0e77 100644 --- a/Src/nmNum/nmPlot/nmGuiPlot.cpp +++ b/Src/nmNum/nmPlot/nmGuiPlot.cpp @@ -493,8 +493,8 @@ void nmGuiPlot::initBoundaryObjFromData(nmDataAnalyzeManager* pDataManager) return; } - // 绑定边界数据到图元对象上 - pRectOutlinePlot->setOutlineData(pOutlineData); + // 通过 Binder 绑定边界数据到图元对象 + m_pGraphicBinder->bindOutlineToGraphic(pRectOutlinePlot, pOutlineData); } else if(pOutlineData->getOutlineType() == NM_Data_Outline_Type::NM_Round_Outline_Type) { // 圆形边界 // 将当前多边形边界对象添加到地图 @@ -504,8 +504,8 @@ void nmGuiPlot::initBoundaryObjFromData(nmDataAnalyzeManager* pDataManager) return; } - // 绑定边界数据到图元对象上 - pPRoundOutlinePlot->setOutlineData(pOutlineData); + // 通过 Binder 绑定边界数据到图元对象 + m_pGraphicBinder->bindOutlineToGraphic(pPRoundOutlinePlot, pOutlineData); } else if(pOutlineData->getOutlineType() == NM_Data_Outline_Type::NM_Polygon_Outline_Type) { // 多边形边界 // 将当前多边形边界对象添加到地图 @@ -515,8 +515,8 @@ void nmGuiPlot::initBoundaryObjFromData(nmDataAnalyzeManager* pDataManager) return; } - // 绑定边界数据到图元对象上 - pPolygonOutlinePlot->setOutlineData(pOutlineData); + // 通过 Binder 绑定边界数据到图元对象 + m_pGraphicBinder->bindOutlineToGraphic(pPolygonOutlinePlot, pOutlineData); } } @@ -1376,11 +1376,15 @@ void nmGuiPlot::slotDeleteOneObj(QString sName, void* obj) if(nmObj) { m_pPlot->removeObjByName(sName); - // 先通过 Binder 清理数据绑定(如果是断层/裂缝等 Binder 管理的类型) + // 先通过 Binder 清理数据绑定(如果是断层/裂缝/边界等 Binder 管理的类型) if (nmObjLineFault* pFault = dynamic_cast(nmObj)) { m_pGraphicBinder->removeFaultBinding(pFault); } else if (nmObjLineCrack* pCrack = dynamic_cast(nmObj)) { m_pGraphicBinder->removeCrackBinding(pCrack); + } else if (dynamic_cast(nmObj) || + dynamic_cast(nmObj) || + dynamic_cast(nmObj)) { + m_pGraphicBinder->removeOutlineBinding(nmObj); } else { // 其他类型回退到旧方式 nmObj->removeData(); diff --git a/Src/nmNum/nmPlot/nmGuiPlotCmdHelper.cpp b/Src/nmNum/nmPlot/nmGuiPlotCmdHelper.cpp index 7a84b91..29cb7d1 100644 --- a/Src/nmNum/nmPlot/nmGuiPlotCmdHelper.cpp +++ b/Src/nmNum/nmPlot/nmGuiPlotCmdHelper.cpp @@ -28,9 +28,13 @@ #include "nmObjRectTool.h" #include "nmObjRectOutlineTool.h" +#include "nmObjRectOutline.h" #include "nmObjRoundTool.h" #include "nmObjRoundOutlineTool.h" +#include "nmObjRoundOutline.h" + +#include "nmObjPolygonOutline.h" #include "nmObjRegionTool.h" @@ -348,7 +352,7 @@ void nmGuiPlotCmdHelper::slotObjPtsFinished(QVector& vec) { } nmObjBase* pObj = pWxPlot->appendOneObj(pTool->getNOT(), sName, vec); - // 断层/裂缝创建逻辑已改由 Binder 负责(创建数据 + 建立信号连接) + // 断层/裂缝/边界创建逻辑已改由 Binder 负责(创建数据 + 建立信号连接) if (pTool->getNOT() == NMOT_Line_Fault) { nmObjLineFault* pFault = dynamic_cast(pObj); if (pFault && pWxPlot->graphicBinder()) { @@ -359,6 +363,24 @@ void nmGuiPlotCmdHelper::slotObjPtsFinished(QVector& vec) { if (pCrack && pWxPlot->graphicBinder()) { pWxPlot->graphicBinder()->createCrackForGraphic(pCrack); } + } else if (pTool->getNOT() == NMOT_RectOutline || + pTool->getNOT() == NMOT_RoundOutline || + pTool->getNOT() == NMOT_PolygonOutline) { + // 先执行 afterCreated(矩形边界会在其中 reorderPoints) + pObj->afterCreated(); + // 再通过 Binder 创建数据并建立绑定 + if (pWxPlot->graphicBinder()) { + nmObjRoundOutline* pRound = dynamic_cast(pObj); + nmObjRectOutline* pRect = dynamic_cast(pObj); + nmObjPolygonOutline* pPolygon = dynamic_cast(pObj); + if (pRound) { + pWxPlot->graphicBinder()->createOutlineForGraphic(pRound); + } else if (pRect) { + pWxPlot->graphicBinder()->createOutlineForGraphic(pRect); + } else if (pPolygon) { + pWxPlot->graphicBinder()->createOutlineForGraphic(pPolygon); + } + } } else { pObj->afterCreated(); } diff --git a/Src/nmNum/nmPlot/nmObjPolygonOutline.cpp b/Src/nmNum/nmPlot/nmObjPolygonOutline.cpp index e56f461..df8fff9 100644 --- a/Src/nmNum/nmPlot/nmObjPolygonOutline.cpp +++ b/Src/nmNum/nmPlot/nmObjPolygonOutline.cpp @@ -9,15 +9,14 @@ #include "nmObjPolygonOutlineTool.h" #include "nmObjPolygonOutline.h" -#include "nmDataLogFile.h" - -#include "nmDataAnalyzeManager.h" +#include "nmPlotGraphicBinder.h" ZX_DEFINE_DYNAMIC(nObjPolygonOutline, nmObjPolygonOutline) nmObjPolygonOutline::nmObjPolygonOutline() { m_sObjTag = "nObjPolygonOutline"; + m_pGraphicBinder = nullptr; nmObjPolygonOutline::init("", NULL, NULL); } @@ -26,13 +25,12 @@ nmObjPolygonOutline::nmObjPolygonOutline(const QString& sName, \ ZxSubAxisY* pAxisY) { m_sObjTag = "nObjPolygonOutline"; + m_pGraphicBinder = nullptr; nmObjPolygonOutline::init(sName, pAxisX, pAxisY); } nmObjPolygonOutline::~nmObjPolygonOutline() { - // 边界数据由DataManager统一释放,图元只保存引用。 - m_outlineData = nullptr; } void nmObjPolygonOutline::init(const QString& sName, \ @@ -40,11 +38,7 @@ void nmObjPolygonOutline::init(const QString& sName, \ ZxSubAxisY* pAxisY) { nmObjPolygon::init(sName, pAxisX, pAxisY); - m_outlineData = nullptr; - - // 连接图元可见性信号和槽 - connect(this, SIGNAL(sigObjVisibleChanged(bool)), - this, SLOT(onObjVisibleChanged(bool))); + m_pGraphicBinder = nullptr; } void nmObjPolygonOutline::initTools() @@ -88,23 +82,18 @@ void nmObjPolygonOutline::fillPtyPano(IxPtyPano* sheet) void nmObjPolygonOutline::onSerialize(ZxSerializer* ser) { nmObjPolygon::onSerialize(ser); - // ser->write("BackgrdColor", m_clrBackgrd); - // TODO,序列化 边界类型数据 ser->write("FlowTypeList", m_vFlowTypeList); } void nmObjPolygonOutline::onDeserialize(ZxSerializer* ser) { nmObjPolygon::onDeserialize(ser); - // ser->read("BackgrdColor", m_clrBackgrd); - // TODO,序列化 边界类型数据 ser->read("FlowTypeList", m_vFlowTypeList); } void nmObjPolygonOutline::onSaveTempl(ZxSerializer* ser) { nmObjPolygon::onSaveTempl(ser); - // ser->write("BackgrdColor", m_clrBackgrd); ser->write("FlowTypeList", m_vFlowTypeList); } @@ -113,20 +102,17 @@ void nmObjPolygonOutline::setAllPos(QVector vecPoss, QVector *pVec nmObjPolygon::setAllPos(vecPoss, pVecIndexes); // 根据点数确定边数,以此来初始化m_vFlowTypeList - // TODO,会不会覆盖从数据库读取的边界类型值! - for(int i = 0; i < vecPoss.count(); i++) { - if (m_vFlowTypeList.count() > i) - { - return; - } + // 仅在列表不足时补充默认值,不阻止信号发射 + while(m_vFlowTypeList.count() < vecPoss.count()) { m_vFlowTypeList.append(NM_OIL_RESERVOIR_OUTLINE_TYPE::OIL_Reservoir_Outline_No_Flow); } + + emit sigOutlinePointsChanged(); } void nmObjPolygonOutline::onLoadTempl(ZxSerializer* ser) { nmObjPolygon::onLoadTempl(ser); - // ser->read("BackgrdColor", m_clrBackgrd); ser->read("FlowTypeList", m_vFlowTypeList); } @@ -135,12 +121,10 @@ void nmObjPolygonOutline::paintBack(QPainter* painter, const ZxPaintParam& param nmObjPolygon::paintBack(painter, param); QVector pts = getPosOf(m_vecPoints); - if (m_outlineData != nullptr) - { - // 动态更新当前边界数据 - m_outlineData->setName(m_sName); - m_outlineData->setOutlinePoints(m_vecPoints); - m_outlineData->setFlowTypeList(m_vFlowTypeList); + // 名称同步:setName 不发信号,在绘制时通过 Binder 同步到数据中心 + if (m_pGraphicBinder) { + m_pGraphicBinder->syncOutlineName(this); + m_pGraphicBinder->syncOutlineVisual(this); } if(isSelected()) { //选中状态下 @@ -158,7 +142,6 @@ void nmObjPolygonOutline::paintBack(QPainter* painter, const ZxPaintParam& param // 如果是选中的边,则显示绿色 if(m_nHitIndex == i && m_oHitOption == OHO_Bound) { - nmDataLogFile::getInstance()->writeLog("select line " + QString::number(i)); QPen pen; pen.setWidth(1); pen.setColor(Qt::green); @@ -175,6 +158,7 @@ void nmObjPolygonOutline::setCurOutlineFlowType(int flowType) { if(m_oHitOption == OHO_Bound) { m_vFlowTypeList[m_nHitIndex] = flowType; + emit sigOutlineFlowTypeChanged(); } } @@ -187,35 +171,14 @@ int nmObjPolygonOutline::getCurOutlineFlowType() return (int)NM_OIL_RESERVOIR_OUTLINE_TYPE::OIL_Reservoir_Outline_UNKNOW; } -nmDataOutline* nmObjPolygonOutline::getOutlineData() const { - return m_outlineData; -} - -void nmObjPolygonOutline::setOutlineData(nmDataOutline* newOutlineData) { - m_outlineData = newOutlineData; -} - void nmObjPolygonOutline::afterCreated() { - m_outlineData = nmDataAnalyzeManager::getCurrentInstance()->createOutline(); - m_outlineData->setName(m_sName); - m_outlineData->setFlowTypeList(m_vFlowTypeList); - m_outlineData->setOutlinePoints(m_vecPoints); - - m_outlineData->setOutlineType(NM_Data_Outline_Type::NM_Polygon_Outline_Type); - nmDataAnalyzeManager::getCurrentInstance()->notifyDataChanged(); + if (m_pGraphicBinder) { + m_pGraphicBinder->createOutlineForGraphic(this); + } } void nmObjPolygonOutline::removeData() { - if (m_outlineData) { - // 从数据中心移除该数据 - nmDataAnalyzeManager::getCurrentInstance()->removeOutlineData(); - //delete m_outlineData; - m_outlineData = nullptr; - } -} - -void nmObjPolygonOutline::onObjVisibleChanged(bool bIsVisible) { - if (m_outlineData != nullptr) { - m_outlineData->setPlotVisible(bIsVisible); - } + if (m_pGraphicBinder) { + m_pGraphicBinder->removeOutlineBinding(this); + } } diff --git a/Src/nmNum/nmPlot/nmObjRectOutline.cpp b/Src/nmNum/nmPlot/nmObjRectOutline.cpp index 95af62e..9143a15 100644 --- a/Src/nmNum/nmPlot/nmObjRectOutline.cpp +++ b/Src/nmNum/nmPlot/nmObjRectOutline.cpp @@ -9,15 +9,13 @@ #include "nmObjRectOutlineTool.h" #include "nmObjRectOutline.h" -#include "nmDataLogFile.h" - -#include "nmDataAnalyzeManager.h" +#include "nmPlotGraphicBinder.h" ZX_DEFINE_DYNAMIC(nObjRectOutline, nmObjRectOutline) nmObjRectOutline::nmObjRectOutline() : m_eChangeOutlineType(RBP_Unknown) - , m_outlineData(nullptr) + , m_pGraphicBinder(nullptr) { m_sObjTag = "nObjRectOutline"; nmObjRectOutline::init("", NULL, NULL); @@ -27,7 +25,7 @@ nmObjRectOutline::nmObjRectOutline(const QString& sName, \ ZxSubAxisX* pAxisX, \ ZxSubAxisY* pAxisY) : m_eChangeOutlineType(RBP_Unknown) - , m_outlineData(nullptr) + , m_pGraphicBinder(nullptr) { m_sObjTag = "nObjRectOutline"; nmObjRectOutline::init(sName, pAxisX, pAxisY); @@ -35,8 +33,6 @@ nmObjRectOutline::nmObjRectOutline(const QString& sName, \ nmObjRectOutline::~nmObjRectOutline() { - // 边界数据由DataManager统一释放,图元只保存引用。 - m_outlineData = nullptr; } void nmObjRectOutline::init(const QString& sName, \ @@ -44,11 +40,7 @@ void nmObjRectOutline::init(const QString& sName, \ ZxSubAxisY* pAxisY) { nmObjRect::init(sName, pAxisX, pAxisY); - m_outlineData = nullptr; - - // 连接图元可见性信号和槽 - connect(this, SIGNAL(sigObjVisibleChanged(bool)), - this, SLOT(onObjVisibleChanged(bool))); + m_pGraphicBinder = nullptr; } void nmObjRectOutline::initTools() @@ -116,30 +108,24 @@ void nmObjRectOutline::fillPtyPano(IxPtyPano* sheet) void nmObjRectOutline::onSerialize(ZxSerializer* ser) { nmObjRect::onSerialize(ser); - // ser->write("BackgrdColor", m_clrBackgrd); - // TODO,序列化 边界类型数据 ser->write("FlowTypeList", m_vFlowTypeList); } void nmObjRectOutline::onDeserialize(ZxSerializer* ser) { nmObjRect::onDeserialize(ser); - // ser->read("BackgrdColor", m_clrBackgrd); - // TODO,序列化 边界类型数据 ser->read("FlowTypeList", m_vFlowTypeList); } void nmObjRectOutline::onLoadTempl(ZxSerializer* ser) { nmObjRect::onLoadTempl(ser); - // ser->read("BackgrdColor", m_clrBackgrd); ser->read("FlowTypeList", m_vFlowTypeList); } void nmObjRectOutline::onSaveTempl(ZxSerializer* ser) { nmObjRect::onSaveTempl(ser); - // ser->write("BackgrdColor", m_clrBackgrd); ser->write("FlowTypeList", m_vFlowTypeList); } @@ -148,14 +134,12 @@ void nmObjRectOutline::setAllPos(QVector vecPoss, QVector *pVecInd nmObjRect::setAllPos(vecPoss, pVecIndexes); // 根据点数确定边数,以此来初始化m_vFlowTypeList - // TODO,会不会覆盖从数据库读取的边界类型值! - for(int i = 0; i < vecPoss.count(); i++) { - if(m_vFlowTypeList.count() > i) { - return; - } - + // 仅在列表不足时补充默认值,不阻止信号发射 + while(m_vFlowTypeList.count() < vecPoss.count()) { m_vFlowTypeList.append(NM_OIL_RESERVOIR_OUTLINE_TYPE::OIL_Reservoir_Outline_No_Flow); } + + emit sigOutlinePointsChanged(); } void nmObjRectOutline::paintBack(QPainter* painter, const ZxPaintParam& param) @@ -166,10 +150,10 @@ void nmObjRectOutline::paintBack(QPainter* painter, const ZxPaintParam& param) nmObjRect::paintBack(painter, param); QVector pts = getPosOf(m_vecPoints); - if(m_outlineData != nullptr) { - // 动态更新当前边界数据 - m_outlineData->setName(m_sName); - m_outlineData->setOutlinePoints(m_vecPoints); + // 名称同步:setName 不发信号,在绘制时通过 Binder 同步到数据中心 + if (m_pGraphicBinder) { + m_pGraphicBinder->syncOutlineName(this); + m_pGraphicBinder->syncOutlineVisual(this); } if(isSelected()) { // 选中状态下 @@ -184,58 +168,12 @@ void nmObjRectOutline::paintBack(QPainter* painter, const ZxPaintParam& param) // 渲染节点 painter->setPen(QColor(0, 0, 128)); painter->drawRect(rect); - - // 如果是选中的边,则显示绿色 - /* - if((m_oHitPos == RBP_Top || m_oHitPos == RBP_Right || m_oHitPos == RBP_Bottom || m_oHitPos == RBP_Left) && m_nRectHitIndex== i) { - nmDataLogFile::getInstance()->writeLog("select line " + QString::number(i)); - QPen pen; - pen.setWidth(1); - pen.setColor(Qt::green); - painter->setPen(pen); - painter->drawLine(pts[i], pts[i == pts.count() - 1 ? 0 : i + 1]); - - } - */ } } painter->restore(); } -nmDataOutline* nmObjRectOutline::getOutlineData() const -{ - return m_outlineData; -} - -void nmObjRectOutline::setOutlineData(nmDataOutline* newOutlineData) -{ - m_outlineData = newOutlineData; -} - -void nmObjRectOutline::afterCreated() -{ - m_outlineData = nmDataAnalyzeManager::getCurrentInstance()->createOutline(); - m_outlineData->setName(m_sName); - m_outlineData->setFlowTypeList(m_vFlowTypeList); - - // 更新m_vecPoints点的顺序 - this->reorderPoints(m_vecPoints); - m_outlineData->setOutlinePoints(m_vecPoints); - - m_outlineData->setOutlineType(NM_Data_Outline_Type::NM_Rect_Outline_Type); - nmDataAnalyzeManager::getCurrentInstance()->notifyDataChanged(); -} - -void nmObjRectOutline::removeData() -{ - if(m_outlineData) { - // 从数据中心移除该数据 - nmDataAnalyzeManager::getCurrentInstance()->removeOutlineData(); - m_outlineData = nullptr; - } -} - void nmObjRectOutline::reorderPoints(QVector& points) { if(points.size() != 4) { @@ -288,63 +226,63 @@ void nmObjRectOutline::reorderPoints(QVector& points) // 上边界流动类型 void nmObjRectOutline::setTopOutlineFlowType(int newValue) { - // 先获取之前的边界类型 - QVector vecFlowTypeList = m_outlineData->getFlowTypeList(); - vecFlowTypeList[0] = newValue; - // 设置上边界流动类型 - m_outlineData->setFlowTypeList(vecFlowTypeList); + m_vFlowTypeList[0] = newValue; + emit sigOutlineFlowTypeChanged(); } int nmObjRectOutline::getTopOutlineFlowType() { - return m_outlineData->getFlowTypeList()[0]; + return m_vFlowTypeList[0]; } // 右边界流动类型 void nmObjRectOutline::setRightOutlineFlowType(int newValue) { - // 先获取之前的边界类型 - QVector vecFlowTypeList = m_outlineData->getFlowTypeList(); - vecFlowTypeList[1] = newValue; // 设置右边界流动类型 - m_outlineData->setFlowTypeList(vecFlowTypeList); + m_vFlowTypeList[1] = newValue; + emit sigOutlineFlowTypeChanged(); } int nmObjRectOutline::getRightOutlineFlowType() { - return m_outlineData->getFlowTypeList()[1]; + return m_vFlowTypeList[1]; } // 下边界流动类型 void nmObjRectOutline::setBottomOutlineFlowType(int newValue) { - // 先获取之前的边界类型 - QVector vecFlowTypeList = m_outlineData->getFlowTypeList(); - vecFlowTypeList[2] = newValue; // 设置下边界流动类型 - m_outlineData->setFlowTypeList(vecFlowTypeList); + m_vFlowTypeList[2] = newValue; + emit sigOutlineFlowTypeChanged(); } int nmObjRectOutline::getBottomOutlineFlowType() { - return m_outlineData->getFlowTypeList()[2]; + return m_vFlowTypeList[2]; } // 左边界流动类型 void nmObjRectOutline::setLeftOutlineFlowType(int newValue) { - // 先获取之前的边界类型 - QVector vecFlowTypeList = m_outlineData->getFlowTypeList(); - vecFlowTypeList[3] = newValue; // 设置左边界流动类型 - m_outlineData->setFlowTypeList(vecFlowTypeList); + m_vFlowTypeList[3] = newValue; + emit sigOutlineFlowTypeChanged(); } int nmObjRectOutline::getLeftOutlineFlowType() { - return m_outlineData->getFlowTypeList()[3]; + return m_vFlowTypeList[3]; } -void nmObjRectOutline::onObjVisibleChanged(bool bIsVisible) +void nmObjRectOutline::afterCreated() +{ + // 矩形边界需要先对点排序,再交给 Binder 创建数据 + reorderPoints(m_vecPoints); + if (m_pGraphicBinder) { + m_pGraphicBinder->createOutlineForGraphic(this); + } +} + +void nmObjRectOutline::removeData() { - if(m_outlineData != nullptr) { - m_outlineData->setPlotVisible(bIsVisible); + if (m_pGraphicBinder) { + m_pGraphicBinder->removeOutlineBinding(this); } } diff --git a/Src/nmNum/nmPlot/nmObjRoundOutline.cpp b/Src/nmNum/nmPlot/nmObjRoundOutline.cpp index 589ae9a..ac0cd68 100644 --- a/Src/nmNum/nmPlot/nmObjRoundOutline.cpp +++ b/Src/nmNum/nmPlot/nmObjRoundOutline.cpp @@ -9,15 +9,14 @@ #include "nmObjRoundOutlineTool.h" #include "nmObjRoundOutline.h" -#include "nmDataLogFile.h" - -#include "nmDataAnalyzeManager.h" +#include "nmPlotGraphicBinder.h" ZX_DEFINE_DYNAMIC(nObjRoundOutline, nmObjRoundOutline) nmObjRoundOutline::nmObjRoundOutline() { m_sObjTag = "nObjRoundOutline"; + m_pGraphicBinder = nullptr; nmObjRoundOutline::init("", NULL, NULL); } @@ -26,13 +25,12 @@ nmObjRoundOutline::nmObjRoundOutline(const QString& sName, \ ZxSubAxisY* pAxisY) { m_sObjTag = "nObjRoundOutline"; + m_pGraphicBinder = nullptr; nmObjRoundOutline::init(sName, pAxisX, pAxisY); } nmObjRoundOutline::~nmObjRoundOutline() { - // 边界数据由DataManager统一释放,图元只保存引用。 - m_outlineData = nullptr; } void nmObjRoundOutline::init(const QString& sName, \ @@ -40,11 +38,7 @@ void nmObjRoundOutline::init(const QString& sName, \ ZxSubAxisY* pAxisY) { nmObjRound::init(sName, pAxisX, pAxisY); - m_outlineData = nullptr; - - // 连接图元可见性信号和槽 - connect(this, SIGNAL(sigObjVisibleChanged(bool)), - this, SLOT(onObjVisibleChanged(bool))); + m_pGraphicBinder = nullptr; } void nmObjRoundOutline::initTools() @@ -66,7 +60,6 @@ bool nmObjRoundOutline::_runHitTest(const QPointF& pt, int& nOption, int& nSubIn void nmObjRoundOutline::fillPtyPano(IxPtyPano* sheet) { nmObjRound::fillPtyPano(sheet); - // TODO,设置边界类型的 IxPtyItem* pProp = ZX_PROP("ObjPolygonOutline.Type", getCurOutlineFlowType, setCurOutlineFlowType); if (NULL != pProp) { QStringList listTags; @@ -82,88 +75,63 @@ void nmObjRoundOutline::setAllPos(QVector vecPoss, QVector *pVecIn { nmObjRound::setAllPos(vecPoss, pVecIndexes); - // 圆形只有一个边 - if (m_vFlowTypeList.count() <1) + if (m_vFlowTypeList.count() < 1) { m_vFlowTypeList.append(NM_OIL_RESERVOIR_OUTLINE_TYPE::OIL_Reservoir_Outline_No_Flow); } + + emit sigOutlinePointsChanged(); } void nmObjRoundOutline::paintBack(QPainter* painter, const ZxPaintParam& param) { nmObjRound::paintBack(painter, param); - // 判断半径是否相同,不相同先修改半径相同 if (m_vecPoints[1].x() != m_vecPoints[1].y()) { - // 重新计算半径 - // 计算半径(绝对值) - double radius = qAbs(m_vecPoints[0].y() - m_vecPoints[2].y()); - - // 更新 vecConvertPoints[1] 为 (radius, radius) - m_vecPoints[1] = QPointF(radius, radius); + double radius = qAbs(m_vecPoints[0].y() - m_vecPoints[2].y()); + m_vecPoints[1] = QPointF(radius, radius); } QVector pts = getPosOf(m_vecPoints); - // 判断半径是否相同,不相同先修改半径相同 if (pts[1].x() != pts[1].y()) { double radius = qAbs(pts[0].y() - pts[2].y()); pts[1] = QPointF(radius, radius); - // 重新计算圆上的四个点 - QPointF center = pts[0]; // 圆心 - - // 上点 (x, y - radius) + QPointF center = pts[0]; pts[2] = QPointF(center.x(), center.y() - radius); - - // 右点 (x + radius, y) pts[3] = QPointF(center.x() + radius, center.y()); - - // 下点 (x, y + radius) pts[4] = QPointF(center.x(), center.y() + radius); - - // 左点 (x - radius, y) pts[5] = QPointF(center.x() - radius, center.y()); } - if (m_outlineData != nullptr) - { - // 动态更新当前边界数据 - m_outlineData->setName(m_sName); - - double qradius = m_vecPoints[2].y() - m_vecPoints[0].y(); // 圆形正上方顶点 y - 圆心 y - m_outlineData->setRadius(qradius); // 半径 - - m_outlineData->setCenter(m_vecPoints[0]); // 圆心 - m_outlineData->setFlowTypeList(m_vFlowTypeList); - - // 将点数组也存入数据中心,方便利用数据直接绘制图元 - m_outlineData->setOutlinePoints(m_vecPoints); + // 名称同步:setName 不发信号,在绘制时通过 Binder 同步到数据中心 + if (m_pGraphicBinder) { + m_pGraphicBinder->syncOutlineName(this); + m_pGraphicBinder->syncOutlineVisual(this); } - if (isSelected()) { //选中状态下 + if (isSelected()) { QPen pen(QBrush(Qt::black), 0.0f, Qt::DotLine); painter->setPen(pen); - painter->drawEllipse(pts[0], pts[1].x(),pts[1].y()); + painter->drawEllipse(pts[0], pts[1].x(), pts[1].y()); for (int i = 2; i < pts.count(); i++) { float w = 2.2f; QPointF pt = pts[i]; QRectF rect(pt.x() - w * 0.5f, pt.y() - w * 0.5f, w, w); - // 渲染节点 painter->setPen(QColor(0, 0, 128)); - painter->drawRect(rect); //四个点画矩形 + painter->drawRect(rect); } - // 如果是选中的边,则显示绿色 if (m_oHitOption == OHO_Inner) { QPen pen; - pen.setWidth(1); // 设置线条宽度 - pen.setColor(Qt::green); // 设置线条颜色 + pen.setWidth(1); + pen.setColor(Qt::green); painter->setPen(pen); - painter->drawEllipse(pts[0], pts[1].x(),pts[1].y()); + painter->drawEllipse(pts[0], pts[1].x(), pts[1].y()); } } painter->restore(); @@ -173,6 +141,7 @@ void nmObjRoundOutline::setCurOutlineFlowType(int flowType) { if (m_oHitOption == OHO_Point || m_oHitOption == OHO_Bound || m_oHitOption == OHO_Inner) { m_vFlowTypeList[0] = flowType; + emit sigOutlineFlowTypeChanged(); } } @@ -181,41 +150,14 @@ int nmObjRoundOutline::getCurOutlineFlowType() return m_vFlowTypeList[0]; } -nmDataOutline* nmObjRoundOutline::getOutlineData() const { - return m_outlineData; -} - -void nmObjRoundOutline::setOutlineData(nmDataOutline* newOutlineData) { - m_outlineData = newOutlineData; -} - void nmObjRoundOutline::afterCreated() { - m_outlineData = nmDataAnalyzeManager::getCurrentInstance()->createOutline(); - m_outlineData->setName(m_sName); - m_outlineData->setFlowTypeList(m_vFlowTypeList); - double qradius = m_vecPoints[2].y() - m_vecPoints[0].y(); // 圆形正上方顶点 y - 圆心 y - m_outlineData->setRadius(qradius); // 半径 - - m_outlineData->setCenter(m_vecPoints[0]); // 圆心 - - m_outlineData->setOutlineType(NM_Data_Outline_Type::NM_Round_Outline_Type); - - // 将点数组也存入数据中心,方便利用数据直接绘制图元 - m_outlineData->setOutlinePoints(m_vecPoints); - nmDataAnalyzeManager::getCurrentInstance()->notifyDataChanged(); + if (m_pGraphicBinder) { + m_pGraphicBinder->createOutlineForGraphic(this); + } } void nmObjRoundOutline::removeData() { - if (m_outlineData) { - // 从数据中心移除该数据 - nmDataAnalyzeManager::getCurrentInstance()->removeOutlineData(); - //delete m_outlineData; - m_outlineData = nullptr; - } -} - -void nmObjRoundOutline::onObjVisibleChanged(bool bIsVisible) { - if (m_outlineData != nullptr) { - m_outlineData->setPlotVisible(bIsVisible); - } + if (m_pGraphicBinder) { + m_pGraphicBinder->removeOutlineBinding(this); + } } diff --git a/Src/nmNum/nmPlot/nmPlotGraphicBinder.cpp b/Src/nmNum/nmPlot/nmPlotGraphicBinder.cpp index 68cdc17..3f773c8 100644 --- a/Src/nmNum/nmPlot/nmPlotGraphicBinder.cpp +++ b/Src/nmNum/nmPlot/nmPlotGraphicBinder.cpp @@ -4,6 +4,11 @@ #include "nmDataFault.h" #include "nmObjLineCrack.h" #include "nmDataFracture.h" +#include "nmObjRoundOutline.h" +#include "nmObjRectOutline.h" +#include "nmObjPolygonOutline.h" +#include "nmDataOutline.h" +#include "nmObjBase.h" #include "nmDataAnalyzeManager.h" #include @@ -91,6 +96,8 @@ void nmPlotGraphicBinder::updateDataMgr(nmDataAnalyzeManager* pDataMgr) m_setBoundGraphics.clear(); m_mapCrackData.clear(); m_setBoundCrackGraphics.clear(); + m_mapOutlineData.clear(); + m_setBoundOutlineGraphics.clear(); m_pDataMgr = pDataMgr; } @@ -418,3 +425,345 @@ void nmPlotGraphicBinder::onGraphicCrackVisibleChanged(bool bVisible) pData->setPlotVisible(bVisible); } + +// ==================== 边界图元绑定 ==================== + +// 圆形边界:用户画完后创建数据并绑定 +void nmPlotGraphicBinder::createOutlineForGraphic(nmObjRoundOutline* pGraphic) +{ + if (!pGraphic || !m_pDataMgr) return; + + // 清理旧边界图元的绑定(数据中心同一时间只持有一个边界数据) + QList oldGraphics = m_mapOutlineData.keys(); + foreach (nmObjBase* pOld, oldGraphics) { + if (pOld != pGraphic) { + _disconnectOutline(pOld); + m_mapOutlineData.remove(pOld); + } + } + + nmDataOutline* pData = m_pDataMgr->createOutline(); + pData->setName(pGraphic->getName()); + pData->setOutlinePoints(pGraphic->getAllValues()); + pData->setFlowTypeList(pGraphic->m_vFlowTypeList); + pData->setOutlineType(NM_Data_Outline_Type::NM_Round_Outline_Type); + + // 视觉属性同步到数据 + pData->setPenWidth(pGraphic->getPen().widthF()); + QColor roundClr = pGraphic->getBackgrdColor(); + pData->setBackgrdColor(roundClr); + pData->setBackgrdAlpha(roundClr.alpha()); + pData->setVisualPropsValid(true); + + double qradius = pGraphic->getAllValues()[2].y() - pGraphic->getAllValues()[0].y(); + pData->setRadius(qradius); + pData->setCenter(pGraphic->getAllValues()[0]); + + m_mapOutlineData[pGraphic] = pData; + m_setBoundOutlineGraphics.insert(pGraphic); + _connectOutline(pGraphic, pData); + + if (m_pDataMgr) { + m_pDataMgr->notifyDataChanged(); + } +} + +// 矩形边界:用户画完后创建数据并绑定 +void nmPlotGraphicBinder::createOutlineForGraphic(nmObjRectOutline* pGraphic) +{ + if (!pGraphic || !m_pDataMgr) return; + + // 清理旧边界图元的绑定(数据中心同一时间只持有一个边界数据) + QList oldGraphics = m_mapOutlineData.keys(); + foreach (nmObjBase* pOld, oldGraphics) { + if (pOld != pGraphic) { + _disconnectOutline(pOld); + m_mapOutlineData.remove(pOld); + } + } + + nmDataOutline* pData = m_pDataMgr->createOutline(); + pData->setName(pGraphic->getName()); + pData->setOutlinePoints(pGraphic->getAllValues()); + pData->setFlowTypeList(pGraphic->m_vFlowTypeList); + pData->setOutlineType(NM_Data_Outline_Type::NM_Rect_Outline_Type); + + pData->setPenWidth(pGraphic->getPen().widthF()); + pData->setBackgrdColor(pGraphic->getBackgrdColor()); + pData->setBackgrdAlpha(pGraphic->getBackgrdAlpha()); + pData->setVisualPropsValid(true); + + m_mapOutlineData[pGraphic] = pData; + m_setBoundOutlineGraphics.insert(pGraphic); + _connectOutline(pGraphic, pData); + + if (m_pDataMgr) { + m_pDataMgr->notifyDataChanged(); + } +} + +// 多边形边界:用户画完后创建数据并绑定 +void nmPlotGraphicBinder::createOutlineForGraphic(nmObjPolygonOutline* pGraphic) +{ + if (!pGraphic || !m_pDataMgr) return; + + // 清理旧边界图元的绑定(数据中心同一时间只持有一个边界数据) + QList oldGraphics = m_mapOutlineData.keys(); + foreach (nmObjBase* pOld, oldGraphics) { + if (pOld != pGraphic) { + _disconnectOutline(pOld); + m_mapOutlineData.remove(pOld); + } + } + + nmDataOutline* pData = m_pDataMgr->createOutline(); + pData->setName(pGraphic->getName()); + pData->setOutlinePoints(pGraphic->getAllValues()); + pData->setFlowTypeList(pGraphic->m_vFlowTypeList); + pData->setOutlineType(NM_Data_Outline_Type::NM_Polygon_Outline_Type); + + pData->setPenWidth(pGraphic->getPen().widthF()); + pData->setBackgrdColor(pGraphic->getBackgrdColor()); + pData->setBackgrdAlpha(pGraphic->getBackgrdAlpha()); + pData->setVisualPropsValid(true); + + m_mapOutlineData[pGraphic] = pData; + m_setBoundOutlineGraphics.insert(pGraphic); + _connectOutline(pGraphic, pData); + + if (m_pDataMgr) { + m_pDataMgr->notifyDataChanged(); + } +} + +// 从文件加载,绑定已有边界数据到已有图元 +void nmPlotGraphicBinder::bindOutlineToGraphic(nmObjBase* pGraphic, nmDataOutline* pData) +{ + if (!pGraphic || !pData) return; + + m_mapOutlineData[pGraphic] = pData; + m_setBoundOutlineGraphics.insert(pGraphic); + + _pushOutlineDataToGraphic(pGraphic, pData); + _connectOutline(pGraphic, pData); +} + +// 删除边界图元前,断开绑定并从数据中心移除 +void nmPlotGraphicBinder::removeOutlineBinding(nmObjBase* pGraphic) +{ + if (!pGraphic) return; + + _disconnectOutline(pGraphic); + m_mapOutlineData.remove(pGraphic); + + if (m_pDataMgr) { + m_pDataMgr->removeOutlineData(); + m_pDataMgr->notifyDataChanged(); + } +} + +// 查找边界图元对应的数据指针 +nmDataOutline* nmPlotGraphicBinder::getOutlineDataFor(nmObjBase* pGraphic) +{ + return m_mapOutlineData.value(pGraphic, nullptr); +} + +// 名称同步:setName 不发信号,由图元在 paintBack 中调用 +void nmPlotGraphicBinder::syncOutlineName(nmObjBase* pGraphic) +{ + if (!pGraphic) return; + nmDataOutline* pData = m_mapOutlineData.value(pGraphic, nullptr); + if (pData && pData->getName() != pGraphic->getName()) { + pData->setName(pGraphic->getName()); + } +} + +// 视觉属性兜底同步:paintBack 中调用,确保画笔宽度、填充色、透明度始终同步到数据中心 +void nmPlotGraphicBinder::syncOutlineVisual(nmObjBase* pGraphic) +{ + if (!pGraphic) return; + nmDataOutline* pData = m_mapOutlineData.value(pGraphic, nullptr); + if (!pData) return; + + // 画笔宽度 + QPen pen = pGraphic->getPen(); + double penWidth = pen.widthF(); + if (pData->getPenWidth() != penWidth) { + pData->setPenWidth(penWidth); + } + + // 填充背景色和透明度 + QColor backgrdColor; + int backgrdAlpha = 0; + if (nmObjRectOutline* pRect = dynamic_cast(pGraphic)) { + backgrdColor = pRect->getBackgrdColor(); + backgrdAlpha = pRect->getBackgrdAlpha(); + } else if (nmObjRoundOutline* pRound = dynamic_cast(pGraphic)) { + backgrdColor = pRound->getBackgrdColor(); + backgrdAlpha = backgrdColor.alpha(); // 圆形透明度嵌入在 QColor 中 + } else if (nmObjPolygonOutline* pPolygon = dynamic_cast(pGraphic)) { + backgrdColor = pPolygon->getBackgrdColor(); + backgrdAlpha = pPolygon->getBackgrdAlpha(); + } + + if (pData->getBackgrdColor().rgb() != backgrdColor.rgb()) { + pData->setBackgrdColor(backgrdColor); + } + if (pData->getBackgrdAlpha() != backgrdAlpha) { + pData->setBackgrdAlpha(backgrdAlpha); + } + + pData->setVisualPropsValid(true); +} + +// 建立边界图元与数据的信号连接(三条信号) +void nmPlotGraphicBinder::_connectOutline(nmObjBase* pGraphic, nmDataOutline* pData) +{ + QObject::connect(pGraphic, SIGNAL(sigOutlinePointsChanged()), + this, SLOT(onGraphicOutlinePointsChanged())); + + QObject::connect(pGraphic, SIGNAL(sigOutlineFlowTypeChanged()), + this, SLOT(onGraphicOutlineFlowTypeChanged())); + + QObject::connect(pGraphic, SIGNAL(sigObjVisibleChanged(bool)), + this, SLOT(onGraphicOutlineVisibleChanged(bool))); + + m_setBoundOutlineGraphics.insert(pGraphic); + + // 注入 Binder 指针到图元 + if (nmObjRoundOutline* pRound = dynamic_cast(pGraphic)) { + pRound->setGraphicBinder(this); + } else if (nmObjRectOutline* pRect = dynamic_cast(pGraphic)) { + pRect->setGraphicBinder(this); + } else if (nmObjPolygonOutline* pPolygon = dynamic_cast(pGraphic)) { + pPolygon->setGraphicBinder(this); + } +} + +// 断开边界图元与本 Binder 的信号连接 +void nmPlotGraphicBinder::_disconnectOutline(nmObjBase* pGraphic) +{ + QObject::disconnect(pGraphic, SIGNAL(sigOutlinePointsChanged()), + this, SLOT(onGraphicOutlinePointsChanged())); + + QObject::disconnect(pGraphic, SIGNAL(sigOutlineFlowTypeChanged()), + this, SLOT(onGraphicOutlineFlowTypeChanged())); + + QObject::disconnect(pGraphic, SIGNAL(sigObjVisibleChanged(bool)), + this, SLOT(onGraphicOutlineVisibleChanged(bool))); + + m_setBoundOutlineGraphics.remove(pGraphic); +} + +// 从边界数据对象读取值,写入图元本地副本(加载时用) +void nmPlotGraphicBinder::_pushOutlineDataToGraphic(nmObjBase* pGraphic, nmDataOutline* pData) +{ + pGraphic->blockSignals(true); + + pGraphic->setName(pData->getName()); + + QVector flowTypes = pData->getFlowTypeList(); + + bool bPushVisual = pData->hasVisualProps(); + + if (nmObjRoundOutline* pRound = dynamic_cast(pGraphic)) { + pRound->m_vFlowTypeList = flowTypes; + if (bPushVisual) { + QPen pen = pRound->getPen(); + pen.setWidthF(pData->getPenWidth()); + pRound->setPen(pen); + QColor clr = pData->getBackgrdColor(); + clr.setAlpha(pData->getBackgrdAlpha()); + pRound->setBackgrdColor(clr); + } + } else if (nmObjRectOutline* pRect = dynamic_cast(pGraphic)) { + pRect->m_vFlowTypeList = flowTypes; + if (bPushVisual) { + QPen pen = pRect->getPen(); + pen.setWidthF(pData->getPenWidth()); + pRect->setPen(pen); + pRect->setBackgrdColor(pData->getBackgrdColor()); + pRect->setBackgrdAlpha(pData->getBackgrdAlpha()); + } + } else if (nmObjPolygonOutline* pPolygon = dynamic_cast(pGraphic)) { + pPolygon->m_vFlowTypeList = flowTypes; + if (bPushVisual) { + QPen pen = pPolygon->getPen(); + pen.setWidthF(pData->getPenWidth()); + pPolygon->setPen(pen); + pPolygon->setBackgrdColor(pData->getBackgrdColor()); + pPolygon->setBackgrdAlpha(pData->getBackgrdAlpha()); + } + } + + pGraphic->blockSignals(false); +} + +// ==================== 边界图元信号 → 数据同步 ==================== + +// 边界点坐标变更 +void nmPlotGraphicBinder::onGraphicOutlinePointsChanged() +{ + nmObjBase* pGraphic = qobject_cast(sender()); + if (!pGraphic) return; + + nmDataOutline* pData = m_mapOutlineData.value(pGraphic, nullptr); + if (!pData) return; + + pData->setOutlinePoints(pGraphic->getAllValues()); + + // 圆形边界额外同步 radius 和 center + if (nmObjRoundOutline* pRound = dynamic_cast(pGraphic)) { + QVector pts = pRound->getAllValues(); + if (pts.count() >= 3) { + double radius = pts[2].y() - pts[0].y(); + pData->setRadius(radius); + pData->setCenter(pts[0]); + } + } + + if (m_pDataMgr) { + m_pDataMgr->notifyDataChanged(); + } +} + +// 边界流动类型变更 +void nmPlotGraphicBinder::onGraphicOutlineFlowTypeChanged() +{ + nmObjBase* pGraphic = qobject_cast(sender()); + if (!pGraphic) return; + + nmDataOutline* pData = m_mapOutlineData.value(pGraphic, nullptr); + if (!pData) return; + + QVector flowTypes; + if (nmObjRoundOutline* pRound = dynamic_cast(pGraphic)) { + flowTypes = pRound->m_vFlowTypeList; + } else if (nmObjRectOutline* pRect = dynamic_cast(pGraphic)) { + flowTypes = pRect->m_vFlowTypeList; + } else if (nmObjPolygonOutline* pPolygon = dynamic_cast(pGraphic)) { + flowTypes = pPolygon->m_vFlowTypeList; + } + + pData->setFlowTypeList(flowTypes); + + if (m_pDataMgr) { + m_pDataMgr->notifyDataChanged(); + } +} + +// 边界可见性变更 +void nmPlotGraphicBinder::onGraphicOutlineVisibleChanged(bool bVisible) +{ + nmObjBase* pGraphic = qobject_cast(sender()); + if (!pGraphic) return; + + nmDataOutline* pData = m_mapOutlineData.value(pGraphic, nullptr); + if (!pData) return; + + pData->setPlotVisible(bVisible); + + if (m_pDataMgr) { + m_pDataMgr->notifyDataChanged(); + } +}