diff --git a/Bin/Config/Lang/cn/nmNum_cn.qm b/Bin/Config/Lang/cn/nmNum_cn.qm
index 56cf88a..f5e67e3 100644
Binary files a/Bin/Config/Lang/cn/nmNum_cn.qm and b/Bin/Config/Lang/cn/nmNum_cn.qm differ
diff --git a/Bin/Config/Lang/cn/nmNum_cn.ts b/Bin/Config/Lang/cn/nmNum_cn.ts
index f699e02..65b9b87 100644
--- a/Bin/Config/Lang/cn/nmNum_cn.ts
+++ b/Bin/Config/Lang/cn/nmNum_cn.ts
@@ -6554,6 +6554,22 @@ Average pressure in contour: %2 MPa
Property Interpolation
属性插值
+
+ Dataset:
+ 数据组:
+
+
+ Add dataset
+ 新建数据组
+
+
+ Delete dataset
+ 删除数据组
+
+
+ Dataset #%1
+ 数据组 #%1
+
Property:
属性:
@@ -6610,6 +6626,14 @@ Average pressure in contour: %2 MPa
Clear
清空
+
+ Show measurement points
+ 显示测点
+
+
+ Show labels
+ 显示标签
+
Kriging Parameters
Kriging参数
diff --git a/Include/nmNum/nmData/nmDataAnalyzeManager.h b/Include/nmNum/nmData/nmDataAnalyzeManager.h
index c908ac2..9512d01 100644
--- a/Include/nmNum/nmData/nmDataAnalyzeManager.h
+++ b/Include/nmNum/nmData/nmDataAnalyzeManager.h
@@ -51,6 +51,47 @@ struct BackgroundImageInfo {
QImage objImage; // 具体的QImage对象
};
+/* 插值测点数据 */
+struct NM_DATA_EXPORT nmPropertyInterpolationPointData {
+ nmPropertyInterpolationPointData()
+ : x(0.0), y(0.0), value(0.0)
+ {
+ }
+
+ nmPropertyInterpolationPointData(double xValue, double yValue, double propertyValue)
+ : x(xValue), y(yValue), value(propertyValue)
+ {
+ }
+
+ double x;
+ double y;
+ double value;
+};
+
+/* 一组属性插值数据及其Kriging参数 */
+struct NM_DATA_EXPORT nmPropertyInterpolationDataSet {
+ nmPropertyInterpolationDataSet()
+ : property("k"),
+ showPoints(true),
+ showLabels(true),
+ nugget(0.01),
+ sill(100.0),
+ range(1000.0),
+ model(0)
+ {
+ }
+
+ QString name;
+ QString property;
+ QVector points;
+ bool showPoints;
+ bool showLabels;
+ double nugget;
+ double sill;
+ double range;
+ int model;
+};
+
enum NM_SOLVER_MODEL_TYPE {
SMT_Oil_ConstPvt = 1,
SMT_Oil_VariablePvt = 2,
@@ -433,6 +474,10 @@ class NM_DATA_EXPORT nmDataAnalyzeManager : public ZxDataObjectBin
// 获取背景图片信息
const BackgroundImageInfo& getBackgroundImageInfo() const;
+ /* 获取及设置属性插值数据组 */
+ QVector getPropertyInterpolationDataSets() const;
+ void setPropertyInterpolationDataSets(const QVector& dataSets);
+
// 统一的读写整个项目数据的方法
// @param filePath JSON文件的路径
// @return 读取成功返回 true,否则返回 false
@@ -647,6 +692,9 @@ class NM_DATA_EXPORT nmDataAnalyzeManager : public ZxDataObjectBin
// 显示设置信息
QVector m_vecDisplaySettings;
+ /* 属性插值数据组 */
+ QVector m_vecPropertyInterpolationDataSets;
+
// 背景图片信息
BackgroundImageInfo m_backgroundImageInfo;
diff --git a/Include/nmNum/nmPlot/nmGuiPlot.h b/Include/nmNum/nmPlot/nmGuiPlot.h
index 3a57ae6..9bb7cce 100644
--- a/Include/nmNum/nmPlot/nmGuiPlot.h
+++ b/Include/nmNum/nmPlot/nmGuiPlot.h
@@ -42,6 +42,9 @@ class NM_PLOT_EXPORT nmGuiPlot : public iGuiPlot {
// Action命令执行
virtual bool runAction(QString sAction) override;
+ // 取消当前地图绘图操作.
+ void cancelActiveTools();
+
// 创建添加一个Obj
nmObjBase* appendOneObj(NM_Obj_Type o, QString& sName, QVector& vec);
nmObjBase* _createOneObj(NM_Obj_Type o, QString& sName);
diff --git a/Include/nmNum/nmPlot/nmGuiPlotCmdHelper.h b/Include/nmNum/nmPlot/nmGuiPlotCmdHelper.h
index 58a8fd4..8c026d9 100644
--- a/Include/nmNum/nmPlot/nmGuiPlotCmdHelper.h
+++ b/Include/nmNum/nmPlot/nmGuiPlotCmdHelper.h
@@ -19,6 +19,9 @@ public:
virtual bool runAction(QString sAction) override;
+ // 取消当前地图绘图操作,并恢复默认操作状态.
+ void cancelActiveTools();
+
// 插入背景
void insertBkImg();
diff --git a/Include/nmNum/nmSubWxs/nmWxPropertyInterpolationDlg.h b/Include/nmNum/nmSubWxs/nmWxPropertyInterpolationDlg.h
index 9c8dc7f..4d9572f 100644
--- a/Include/nmNum/nmSubWxs/nmWxPropertyInterpolationDlg.h
+++ b/Include/nmNum/nmSubWxs/nmWxPropertyInterpolationDlg.h
@@ -2,42 +2,118 @@
#define NMWXPROPERTYINTERPOLATIONDLG_H
#include "iDlgBase.h"
+#include "nmDataAnalyzeManager.h"
#include "nmSubWxs_global.h"
+#include
+#include
+#include
+
+class QCheckBox;
class QComboBox;
class QDoubleSpinBox;
+class QEvent;
class QLineEdit;
+class QPointF;
class QPushButton;
class QTableWidget;
+class QTableWidgetItem;
+class nmGuiPlot;
+class nmObjPoint;
class NM_SUB_WXS_EXPORT nmWxPropertyInterpolationDlg : public iDlgBase
{
+ Q_OBJECT
+
public:
- explicit nmWxPropertyInterpolationDlg(QWidget* parent = 0);
+ explicit nmWxPropertyInterpolationDlg(nmGuiPlot* plot,
+ nmDataAnalyzeManager* dataManager,
+ QWidget* parent = 0);
+ ~nmWxPropertyInterpolationDlg();
+
+protected:
+ bool eventFilter(QObject* watched, QEvent* event);
+
+private slots:
+ void onDataSetChanged(int index);
+ void onAddDataSet();
+ void onDeleteDataSet();
+ void onDataSetNameChanged(const QString& name);
+ void onCurrentDataSetEdited();
+ void onMapPickToggled(bool checked);
+ void onMapClicked(const QPointF& position);
+ void onPointSelectionChanged();
+ void onPointItemChanged(QTableWidgetItem* item);
+ void onDeleteSelectedPoint();
+ void onClearPoints();
+ void onShowPointsToggled(bool checked);
+ void onShowLabelsToggled(bool checked);
private:
- // 初始化属性插值界面
+ // 初始化界面及持久化数据组.
void initInterpolationUI();
+ void initializeDataSets();
+ nmPropertyInterpolationDataSet createDefaultDataSet();
+ QString nextDataSetName();
+ void loadDataSet(int index);
+ void clearCurrentDataSet();
+ void saveCurrentDataSet();
+ void syncDataSetsToManager(bool markModified);
+ void updateDataSetButtons();
+
+ // 管理测点表格和地图上的临时标记.
+ void appendPoint(const QPointF& valuePoint);
+ void appendPointRow(const nmPropertyInterpolationPointData& point,
+ const QString& markerName);
+ QString createMarker(const QPointF& valuePosition,
+ double value,
+ bool showPoints,
+ bool showLabels);
+ void createMarkersForAllDataSets();
+ void removeDataSetMarkers(int dataSetIndex);
+ void removeAllMarkers();
+ QString markerNameAt(int row) const;
+ nmObjPoint* markerByName(const QString& markerName) const;
+ nmObjPoint* markerAt(int row) const;
+ void removeMarkerByName(const QString& markerName);
+ void clearTableSelection();
+ void updatePointButtons();
+ void updateCurrentMarkerVisibility();
private:
- // 插值属性及名称
+ QPointer m_pPlot;
+ QPointer m_pDataManager;
+
+ // 多组插值数据.
+ QComboBox* m_pDataSetCombo;
+ QPushButton* m_pAddDataSetButton;
+ QPushButton* m_pDeleteDataSetButton;
+ QVector m_vecDataSets;
+ QVector m_vecMarkerNames;
+ int m_nCurrentDataSetIndex;
+ int m_nNextPointId;
+ bool m_bUpdatingUi;
+
+ // 当前数据组的属性及名称.
QComboBox* m_pPropertyCombo;
QLineEdit* m_pNameEdit;
- // 测点数据录入
+ // 测点数据录入.
QDoubleSpinBox* m_pNewValueSpin;
QPushButton* m_pMapPickButton;
QTableWidget* m_pPointTable;
QPushButton* m_pDeletePointButton;
QPushButton* m_pClearPointsButton;
+ QCheckBox* m_pShowPointsCheck;
+ QCheckBox* m_pShowLabelsCheck;
- // Kriging插值参数
+ // Kriging插值参数.
QDoubleSpinBox* m_pNuggetSpin;
QDoubleSpinBox* m_pSillSpin;
QDoubleSpinBox* m_pRangeSpin;
QComboBox* m_pModelCombo;
- // 结果预览及应用
+ // 结果预览及应用.
QPushButton* m_pPreviewButton;
QPushButton* m_pApplyButton;
};
diff --git a/Src/nmNum/nmData/nmDataAnalyzeManager.cpp b/Src/nmNum/nmData/nmDataAnalyzeManager.cpp
index 87c9380..343d60f 100644
--- a/Src/nmNum/nmData/nmDataAnalyzeManager.cpp
+++ b/Src/nmNum/nmData/nmDataAnalyzeManager.cpp
@@ -65,6 +65,7 @@
#include "nmDataTimeStepSetting.h"
+#include
#include
#include
#include
@@ -3353,6 +3354,17 @@ const BackgroundImageInfo& nmDataAnalyzeManager::getBackgroundImageInfo() const
return m_backgroundImageInfo;
}
+QVector nmDataAnalyzeManager::getPropertyInterpolationDataSets() const
+{
+ return m_vecPropertyInterpolationDataSets;
+}
+
+void nmDataAnalyzeManager::setPropertyInterpolationDataSets(
+ const QVector& dataSets)
+{
+ m_vecPropertyInterpolationDataSets = dataSets;
+}
+
// 从 JSON 文件读取数据到 C++ 对象
bool nmDataAnalyzeManager::ReadProjectData(const QString & filePath)
{
@@ -3400,6 +3412,7 @@ bool nmDataAnalyzeManager::ReadProjectData(const QString & filePath)
}
m_vecLayers.clear();
+ m_vecPropertyInterpolationDataSets.clear();
if(m_reservoirData) {
delete m_reservoirData;
@@ -3517,7 +3530,66 @@ bool nmDataAnalyzeManager::ReadProjectData(const QString & filePath)
}
}
- // 解析 "Reservoir" 对象
+ /* 读取属性插值数据组;旧成果没有该节点时保持为空 */
+ if(doc.HasMember("PropertyInterpolationDataSets") &&
+ doc["PropertyInterpolationDataSets"].IsArray()) {
+ const rapidjson::Value& dataSetsJson = doc["PropertyInterpolationDataSets"];
+
+ for(rapidjson::SizeType i = 0; i < dataSetsJson.Size(); ++i) {
+ const rapidjson::Value& dataSetJson = dataSetsJson[i];
+ if(!dataSetJson.IsObject()) {
+ continue;
+ }
+
+ nmPropertyInterpolationDataSet dataSet;
+ if(dataSetJson.HasMember("Name") && dataSetJson["Name"].IsString()) {
+ dataSet.name = QString::fromUtf8(dataSetJson["Name"].GetString());
+ }
+ if(dataSetJson.HasMember("Property") && dataSetJson["Property"].IsString()) {
+ dataSet.property = QString::fromUtf8(dataSetJson["Property"].GetString());
+ }
+ if(dataSetJson.HasMember("ShowPoints") && dataSetJson["ShowPoints"].IsBool()) {
+ dataSet.showPoints = dataSetJson["ShowPoints"].GetBool();
+ }
+ if(dataSetJson.HasMember("ShowLabels") && dataSetJson["ShowLabels"].IsBool()) {
+ dataSet.showLabels = dataSetJson["ShowLabels"].GetBool();
+ }
+ if(dataSetJson.HasMember("Nugget") && dataSetJson["Nugget"].IsNumber()) {
+ dataSet.nugget = dataSetJson["Nugget"].GetDouble();
+ }
+ if(dataSetJson.HasMember("Sill") && dataSetJson["Sill"].IsNumber()) {
+ dataSet.sill = dataSetJson["Sill"].GetDouble();
+ }
+ if(dataSetJson.HasMember("Range") && dataSetJson["Range"].IsNumber()) {
+ dataSet.range = dataSetJson["Range"].GetDouble();
+ }
+ if(dataSetJson.HasMember("Model") && dataSetJson["Model"].IsInt()) {
+ dataSet.model = dataSetJson["Model"].GetInt();
+ }
+
+ if(dataSetJson.HasMember("Points") && dataSetJson["Points"].IsArray()) {
+ const rapidjson::Value& pointsJson = dataSetJson["Points"];
+ for(rapidjson::SizeType pointIndex = 0; pointIndex < pointsJson.Size(); ++pointIndex) {
+ const rapidjson::Value& pointJson = pointsJson[pointIndex];
+ if(!pointJson.IsObject() ||
+ !pointJson.HasMember("X") || !pointJson["X"].IsNumber() ||
+ !pointJson.HasMember("Y") || !pointJson["Y"].IsNumber() ||
+ !pointJson.HasMember("Value") || !pointJson["Value"].IsNumber()) {
+ continue;
+ }
+
+ dataSet.points.append(nmPropertyInterpolationPointData(
+ pointJson["X"].GetDouble(),
+ pointJson["Y"].GetDouble(),
+ pointJson["Value"].GetDouble()));
+ }
+ }
+
+ m_vecPropertyInterpolationDataSets.append(dataSet);
+ }
+ }
+
+ /* 解析 "Reservoir" 对象 */
if(doc.HasMember("Reservoir") && doc["Reservoir"].IsObject()) {
m_reservoirData = new nmDataReservoir;
m_reservoirData->FromJsonValue(doc["Reservoir"]);
@@ -3736,6 +3808,42 @@ bool nmDataAnalyzeManager::WriteProjectData(const QString & filePath)
doc.AddMember("Layers", layersJsonArray, allocator);
+ /* 保存属性插值数据组 */
+ rapidjson::Value interpolationDataSetsJson(rapidjson::kArrayType);
+ for(int dataSetIndex = 0;
+ dataSetIndex < m_vecPropertyInterpolationDataSets.size();
+ ++dataSetIndex) {
+ const nmPropertyInterpolationDataSet& dataSet =
+ m_vecPropertyInterpolationDataSets[dataSetIndex];
+ rapidjson::Value dataSetJson(rapidjson::kObjectType);
+
+ QByteArray nameUtf8 = dataSet.name.toUtf8();
+ QByteArray propertyUtf8 = dataSet.property.toUtf8();
+ dataSetJson.AddMember("Name",
+ rapidjson::Value(nameUtf8.constData(), allocator).Move(), allocator);
+ dataSetJson.AddMember("Property",
+ rapidjson::Value(propertyUtf8.constData(), allocator).Move(), allocator);
+ dataSetJson.AddMember("ShowPoints", dataSet.showPoints, allocator);
+ dataSetJson.AddMember("ShowLabels", dataSet.showLabels, allocator);
+ dataSetJson.AddMember("Nugget", dataSet.nugget, allocator);
+ dataSetJson.AddMember("Sill", dataSet.sill, allocator);
+ dataSetJson.AddMember("Range", dataSet.range, allocator);
+ dataSetJson.AddMember("Model", dataSet.model, allocator);
+
+ rapidjson::Value pointsJson(rapidjson::kArrayType);
+ for(int pointIndex = 0; pointIndex < dataSet.points.size(); ++pointIndex) {
+ const nmPropertyInterpolationPointData& point = dataSet.points[pointIndex];
+ rapidjson::Value pointJson(rapidjson::kObjectType);
+ pointJson.AddMember("X", point.x, allocator);
+ pointJson.AddMember("Y", point.y, allocator);
+ pointJson.AddMember("Value", point.value, allocator);
+ pointsJson.PushBack(pointJson, allocator);
+ }
+ dataSetJson.AddMember("Points", pointsJson, allocator);
+ interpolationDataSetsJson.PushBack(dataSetJson, allocator);
+ }
+ doc.AddMember("PropertyInterpolationDataSets", interpolationDataSetsJson, allocator);
+
// 序列化 "Reservoir"
if(m_reservoirData) {
rapidjson::Value reservoirJson(rapidjson::kObjectType);
diff --git a/Src/nmNum/nmData/nmDataJsonTools.cpp b/Src/nmNum/nmData/nmDataJsonTools.cpp
index cadf570..36ba197 100644
--- a/Src/nmNum/nmData/nmDataJsonTools.cpp
+++ b/Src/nmNum/nmData/nmDataJsonTools.cpp
@@ -7,7 +7,6 @@
// RapidJSON 内部使用 char*,这里需要转换为 std::string
#include
#include
-#include
#include
#include "rapidjson/document.h"
@@ -211,39 +210,34 @@ bool nmDataJsonTools::WriteDomToFile(const rapidjson::Document& doc, const QStri
rapidjson::PrettyWriter writer(buffer); // 使用 PrettyWriter 进行美化输出
doc.Accept(writer);
- // 将字符串写入文件
+ /* RapidJSON输出为UTF-8字节,直接写入可避免中文被本地编码再次转换 */
QFile file(filePath);
- if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
qDebug() << "Error: Could not open file for writing:" << filePath;
return false;
}
- QTextStream out(&file);
- out << buffer.GetString();
+ const qint64 bufferSize = static_cast(buffer.GetSize());
+ const qint64 writtenSize = file.write(buffer.GetString(), bufferSize);
file.close();
- return true;
+ return writtenSize == bufferSize;
}
// 从文件读取 JSON 并解析到 RapidJSON Document
bool nmDataJsonTools::ReadDomFromFile(const QString& filePath, rapidjson::Document& doc)
{
QFile file(filePath);
- if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ if (!file.open(QIODevice::ReadOnly)) {
qDebug() << "Error: Could not open file for reading:" << filePath;
return false;
}
- QTextStream in(&file);
- QString jsonString = in.readAll();
+ const QByteArray jsonData = file.readAll();
file.close();
- // 将 QString 转换为 std::string
- QByteArray byteArray = jsonString.toUtf8();
- std::string stdJsonString = byteArray.constData();
-
- // 解析 JSON 字符串到 RapidJSON Document
- doc.Parse(stdJsonString.c_str());
+ /* 文件内容保持RapidJSON所需的UTF-8编码 */
+ doc.Parse(jsonData.constData());
if (doc.HasParseError()) {
qDebug() << "Error parsing JSON from file:" << filePath << "Error:" << doc.GetParseError();
@@ -251,4 +245,4 @@ bool nmDataJsonTools::ReadDomFromFile(const QString& filePath, rapidjson::Docume
}
return true;
-}
\ No newline at end of file
+}
diff --git a/Src/nmNum/nmPlot/nmGuiPlot.cpp b/Src/nmNum/nmPlot/nmGuiPlot.cpp
index dd41ffe..2e39630 100644
--- a/Src/nmNum/nmPlot/nmGuiPlot.cpp
+++ b/Src/nmNum/nmPlot/nmGuiPlot.cpp
@@ -167,6 +167,14 @@ bool nmGuiPlot::runAction(QString sAction)
return m_pCmdHelper->runAction(sAction);
}
+void nmGuiPlot::cancelActiveTools()
+{
+ nmGuiPlotCmdHelper* helper = dynamic_cast(m_pCmdHelper);
+ if(helper != NULL) {
+ helper->cancelActiveTools();
+ }
+}
+
void nmGuiPlot::initDefultGeoObj()
{
diff --git a/Src/nmNum/nmPlot/nmGuiPlotCmdHelper.cpp b/Src/nmNum/nmPlot/nmGuiPlotCmdHelper.cpp
index 03d6d16..836329e 100644
--- a/Src/nmNum/nmPlot/nmGuiPlotCmdHelper.cpp
+++ b/Src/nmNum/nmPlot/nmGuiPlotCmdHelper.cpp
@@ -161,6 +161,7 @@ bool nmGuiPlotCmdHelper::runAction(QString sAction) {
pPlot->appendTools(pObjTool);
connect(pObjTool, SIGNAL(sigPtsFinished(QVector&)), \
this, SLOT(slotObjPtsFinished(QVector&)));
+ m_activeTools.insert(pObjTool->getNOT(), pObjTool);
return true;
} else if (_isSame(sAction, "nmInsertObjPointWell")) {
nmObjToolBase* pObjTool = new nmObjPointWellTool();
@@ -169,6 +170,7 @@ bool nmGuiPlotCmdHelper::runAction(QString sAction) {
pPlot->appendTools(pObjTool);
connect(pObjTool, SIGNAL(sigPtsFinished(QVector&)), \
this, SLOT(slotObjPtsFinished(QVector&)));
+ m_activeTools.insert(pObjTool->getNOT(), pObjTool);
return true;
} else if (_isSame(sAction, "nmInsertObjLine")) {
nmObjToolBase* pObjTool = new nmObjLineTool();
@@ -176,6 +178,7 @@ bool nmGuiPlotCmdHelper::runAction(QString sAction) {
pPlot->appendTools(pObjTool);
connect(pObjTool, SIGNAL(sigPtsFinished(QVector&)), \
this, SLOT(slotObjPtsFinished(QVector&)));
+ m_activeTools.insert(pObjTool->getNOT(), pObjTool);
return true;
} else if (_isSame(sAction, "nmInsertObjPolygon")) {
nmObjToolBase* pObjTool = new nmObjPolygonTool();
@@ -183,6 +186,7 @@ bool nmGuiPlotCmdHelper::runAction(QString sAction) {
pPlot->appendTools(pObjTool);
connect(pObjTool, SIGNAL(sigPtsFinished(QVector&)), \
this, SLOT(slotObjPtsFinished(QVector&)));
+ m_activeTools.insert(pObjTool->getNOT(), pObjTool);
return true;
} else if (_isSame(sAction, "nmInsertObjPolygonOutline")) {
nmObjToolBase* pObjTool = new nmObjPolygonOutlineTool();
@@ -190,6 +194,7 @@ bool nmGuiPlotCmdHelper::runAction(QString sAction) {
pPlot->appendTools(pObjTool);
connect(pObjTool, SIGNAL(sigPtsFinished(QVector&)), \
this, SLOT(slotObjPtsFinished(QVector&)));
+ m_activeTools.insert(pObjTool->getNOT(), pObjTool);
return true;
} else if (_isSame(sAction, "nmInsertObjRect")) {
nmObjToolBase* pObjTool = new nmObjRectTool(); //矩形对象工具类
@@ -197,6 +202,7 @@ bool nmGuiPlotCmdHelper::runAction(QString sAction) {
pPlot->appendTools(pObjTool);
connect(pObjTool, SIGNAL(sigPtsFinished(QVector&)), \
this, SLOT(slotObjPtsFinished(QVector&)));
+ m_activeTools.insert(pObjTool->getNOT(), pObjTool);
return true;
} else if (_isSame(sAction, "nmInsertObjRectOutline")) {
nmObjToolBase* pObjTool = new nmObjRectOutlineTool(); //矩形边界工具类
@@ -204,6 +210,7 @@ bool nmGuiPlotCmdHelper::runAction(QString sAction) {
pPlot->appendTools(pObjTool);
connect(pObjTool, SIGNAL(sigPtsFinished(QVector&)), \
this, SLOT(slotObjPtsFinished(QVector&)));
+ m_activeTools.insert(pObjTool->getNOT(), pObjTool);
return true;
} else if (_isSame(sAction, "nmInsertObjRound")) {
nmObjToolBase* pObjTool = new nmObjRoundTool(); //圆形对象工具类
@@ -211,6 +218,7 @@ bool nmGuiPlotCmdHelper::runAction(QString sAction) {
pPlot->appendTools(pObjTool);
connect(pObjTool, SIGNAL(sigPtsFinished(QVector&)), \
this, SLOT(slotObjPtsFinished(QVector&)));
+ m_activeTools.insert(pObjTool->getNOT(), pObjTool);
return true;
} else if (_isSame(sAction, "nmInsertObjRoundOutline")) {
nmObjToolBase* pObjTool = new nmObjRoundOutlineTool(); //圆形边界工具类
@@ -218,6 +226,7 @@ bool nmGuiPlotCmdHelper::runAction(QString sAction) {
pPlot->appendTools(pObjTool);
connect(pObjTool, SIGNAL(sigPtsFinished(QVector&)), \
this, SLOT(slotObjPtsFinished(QVector&)));
+ m_activeTools.insert(pObjTool->getNOT(), pObjTool);
return true;
} else if (_isSame(sAction, "nmInsertObjLineCrack")) {
nmObjToolBase* pObjTool = new nmObjLineCrackTool();
@@ -298,6 +307,21 @@ bool nmGuiPlotCmdHelper::runAction(QString sAction) {
return iGuiPlotCmdHelper::runAction(sAction);
}
+void nmGuiPlotCmdHelper::cancelActiveTools()
+{
+ nmGuiPlot* pWxPlot = dynamic_cast(m_pGuiPlot);
+ if(pWxPlot == nullptr || pWxPlot->m_pPlot == nullptr ||
+ pWxPlot->m_pPlotView == nullptr) {
+ return;
+ }
+
+ foreach (nmObjToolBase* activeTool, m_activeTools.values()) {
+ pWxPlot->m_pPlot->removeTools(activeTool);
+ }
+ m_activeTools.clear();
+ finalWithAcm(true, true);
+}
+
void nmGuiPlotCmdHelper::slotObjPtsFinished(QVector& vec) {
nmObjToolBase* pTool = dynamic_cast(sender());
if (NULL == pTool) {
diff --git a/Src/nmNum/nmSubWnd/nmSubWndMain.cpp b/Src/nmNum/nmSubWnd/nmSubWndMain.cpp
index df48794..1f2b236 100644
--- a/Src/nmNum/nmSubWnd/nmSubWndMain.cpp
+++ b/Src/nmNum/nmSubWnd/nmSubWndMain.cpp
@@ -1446,7 +1446,8 @@ QWidget* nmSubWndMain::showPointerPosDialog()
QWidget* nmSubWndMain::showPropertyInterpolationDialog()
{
- nmWxPropertyInterpolationDlg* interpolationDlg = new nmWxPropertyInterpolationDlg(this);
+ nmWxPropertyInterpolationDlg* interpolationDlg = new nmWxPropertyInterpolationDlg(
+ m_pWxPlot, nmDataAnalyzeManager::getCurrentInstance(), this);
markDialogCmdOpened(5126);
interpolationDlg->setObjectName("nmPropertyInterpolationDialog");
// 关闭窗口时自动释放,并恢复菜单命令的可用状态
diff --git a/Src/nmNum/nmSubWxs/nmWxPropertyInterpolationDlg.cpp b/Src/nmNum/nmSubWxs/nmWxPropertyInterpolationDlg.cpp
index 950be6c..ac076ff 100644
--- a/Src/nmNum/nmSubWxs/nmWxPropertyInterpolationDlg.cpp
+++ b/Src/nmNum/nmSubWxs/nmWxPropertyInterpolationDlg.cpp
@@ -1,28 +1,43 @@
#include "nmWxPropertyInterpolationDlg.h"
#include
+#include
+#include
#include
#include
#include
+#include
#include
#include
#include
#include
+#include
#include
#include
+#include
+#include
#include
+#include
#include
+#include
+#include
#include
+#include "nmGuiPlot.h"
+#include "nmObjPoint.h"
+#include "tCurvePlotView.h"
+#include "ZxObjText.h"
+#include "ZxPlot.h"
+
namespace
{
-// 使用独立翻译上下文,便于统一维护对话框文本
+// 使用独立翻译上下文,便于统一维护对话框文本.
QString interpolationText(const char* sourceText)
{
return QCoreApplication::translate("nmWxPropertyInterpolationDlg", sourceText);
}
-// 创建统一格式的非负数值输入框
+// 创建统一格式的非负数值输入框.
QDoubleSpinBox* createNumberSpinBox(QWidget* parent, double value)
{
QDoubleSpinBox* spinBox = new QDoubleSpinBox(parent);
@@ -32,10 +47,82 @@ QDoubleSpinBox* createNumberSpinBox(QWidget* parent, double value)
spinBox->setButtonSymbols(QAbstractSpinBox::NoButtons);
return spinBox;
}
+
+// 插值测点使用独立的小方块标记,避免与井图元混淆.
+class PropertyInterpolationMarker : public nmObjPoint
+{
+public:
+ PropertyInterpolationMarker(const QString& name,
+ ZxSubAxisX* axisX,
+ ZxSubAxisY* axisY)
+ : nmObjPoint(name, axisX, axisY)
+ {
+ setDotRadius(1.0);
+ }
+
+ virtual bool drawWellPos(QPainter* painter, QPointF point) override
+ {
+ if(painter == NULL) {
+ return false;
+ }
+
+ const QTransform transform = painter->combinedTransform();
+ qreal scaleX = qAbs(transform.m11());
+ qreal scaleY = qAbs(transform.m22());
+
+ if(scaleX < 0.0001) {
+ scaleX = 1.0;
+ }
+
+ if(scaleY < 0.0001) {
+ scaleY = 1.0;
+ }
+
+ const qreal halfPixelSize = 3.0;
+ QRectF markerRect(point.x() - halfPixelSize / scaleX,
+ point.y() - halfPixelSize / scaleY,
+ halfPixelSize * 2.0 / scaleX,
+ halfPixelSize * 2.0 / scaleY);
+
+ painter->save();
+ QPen pen(QColor(0, 25, 100));
+ pen.setWidthF(1.0);
+ pen.setCosmetic(true);
+ painter->setPen(pen);
+ painter->setBrush(QColor(0, 70, 200));
+ painter->drawRect(markerRect);
+ painter->restore();
+ return true;
+ }
+};
+
+void setMarkerLabel(nmObjPoint* marker, const QString& text)
+{
+ if(marker == NULL || marker->getChildren().isEmpty()) {
+ return;
+ }
+
+ ZxObjText* label = dynamic_cast(marker->at(0));
+ if(label != NULL) {
+ label->setText(text);
+ label->setTextColor(QColor(30, 30, 30));
+ }
+}
}
-nmWxPropertyInterpolationDlg::nmWxPropertyInterpolationDlg(QWidget* parent)
+nmWxPropertyInterpolationDlg::nmWxPropertyInterpolationDlg(
+ nmGuiPlot* plot,
+ nmDataAnalyzeManager* dataManager,
+ QWidget* parent)
: iDlgBase(parent),
+ m_pPlot(plot),
+ m_pDataManager(dataManager),
+ m_pDataSetCombo(NULL),
+ m_pAddDataSetButton(NULL),
+ m_pDeleteDataSetButton(NULL),
+ m_nCurrentDataSetIndex(-1),
+ m_nNextPointId(0),
+ m_bUpdatingUi(true),
m_pPropertyCombo(NULL),
m_pNameEdit(NULL),
m_pNewValueSpin(NULL),
@@ -43,6 +130,8 @@ nmWxPropertyInterpolationDlg::nmWxPropertyInterpolationDlg(QWidget* parent)
m_pPointTable(NULL),
m_pDeletePointButton(NULL),
m_pClearPointsButton(NULL),
+ m_pShowPointsCheck(NULL),
+ m_pShowLabelsCheck(NULL),
m_pNuggetSpin(NULL),
m_pSillSpin(NULL),
m_pRangeSpin(NULL),
@@ -56,25 +145,66 @@ nmWxPropertyInterpolationDlg::nmWxPropertyInterpolationDlg(QWidget* parent)
setMinimumSize(520, 620);
resize(560, 680);
initInterpolationUI();
+ initializeDataSets();
+
+ if(qApp != NULL) {
+ qApp->installEventFilter(this);
+ }
+}
+
+nmWxPropertyInterpolationDlg::~nmWxPropertyInterpolationDlg()
+{
+ if(qApp != NULL) {
+ qApp->removeEventFilter(this);
+ }
+
+ onMapPickToggled(false);
+ saveCurrentDataSet();
+ syncDataSetsToManager(false);
+ removeAllMarkers();
}
void nmWxPropertyInterpolationDlg::initInterpolationUI()
{
QVBoxLayout* mainLayout = new QVBoxLayout(this);
- // 插值属性及名称设置
+ // 数据组创建、切换及删除.
+ QHBoxLayout* dataSetSelectLayout = new QHBoxLayout;
+ dataSetSelectLayout->addWidget(new QLabel(interpolationText("Dataset:"), this));
+ m_pDataSetCombo = new QComboBox(this);
+ dataSetSelectLayout->addWidget(m_pDataSetCombo, 1);
+
+ QString iconDir = QCoreApplication::applicationDirPath();
+ iconDir = iconDir.section('/', 0, -2) + "/Res/Icon/";
+
+ m_pAddDataSetButton = new QPushButton(this);
+ m_pAddDataSetButton->setIcon(QIcon(iconDir + "Add.png"));
+ m_pAddDataSetButton->setIconSize(QSize(18, 18));
+ m_pAddDataSetButton->setFixedSize(28, 28);
+ m_pAddDataSetButton->setToolTip(interpolationText("Add dataset"));
+ dataSetSelectLayout->addWidget(m_pAddDataSetButton);
+
+ m_pDeleteDataSetButton = new QPushButton(this);
+ m_pDeleteDataSetButton->setIcon(QIcon(iconDir + "NmDelete.png"));
+ m_pDeleteDataSetButton->setIconSize(QSize(18, 18));
+ m_pDeleteDataSetButton->setFixedSize(28, 28);
+ m_pDeleteDataSetButton->setToolTip(interpolationText("Delete dataset"));
+ dataSetSelectLayout->addWidget(m_pDeleteDataSetButton);
+ mainLayout->addLayout(dataSetSelectLayout);
+
+ // 当前数据组的名称和属性.
QFormLayout* dataSetLayout = new QFormLayout;
+ m_pNameEdit = new QLineEdit(this);
+ dataSetLayout->addRow(interpolationText("Name:"), m_pNameEdit);
+
m_pPropertyCombo = new QComboBox(this);
m_pPropertyCombo->addItem(interpolationText("Permeability k"), QString("k"));
m_pPropertyCombo->addItem(interpolationText("Porosity phi"), QString("phi"));
m_pPropertyCombo->addItem(interpolationText("Reservoir thickness h"), QString("h"));
dataSetLayout->addRow(interpolationText("Property:"), m_pPropertyCombo);
-
- m_pNameEdit = new QLineEdit(interpolationText("Permeability"), this);
- dataSetLayout->addRow(interpolationText("Name:"), m_pNameEdit);
mainLayout->addLayout(dataSetLayout);
- // 测点数据录入区域
+ // 测点数据录入区域.
QGroupBox* pointGroup = new QGroupBox(interpolationText("Measurement Points"), this);
QVBoxLayout* pointLayout = new QVBoxLayout(pointGroup);
@@ -84,12 +214,12 @@ void nmWxPropertyInterpolationDlg::initInterpolationUI()
newPointLayout->addWidget(m_pNewValueSpin, 1);
m_pMapPickButton = new QPushButton(interpolationText("Select on Map"), pointGroup);
m_pMapPickButton->setCheckable(true);
- // 地图选点功能将在后续阶段接入
- m_pMapPickButton->setEnabled(false);
+ m_pMapPickButton->setEnabled(!m_pPlot.isNull() &&
+ m_pPlot->m_pPlotView != NULL &&
+ m_pPlot->m_pPlot != NULL);
newPointLayout->addWidget(m_pMapPickButton);
pointLayout->addLayout(newPointLayout);
- // 每个测点保存坐标及对应的属性值
m_pPointTable = new QTableWidget(0, 3, pointGroup);
QStringList headers;
headers << interpolationText("X") << interpolationText("Y") << interpolationText("Value");
@@ -100,7 +230,6 @@ void nmWxPropertyInterpolationDlg::initInterpolationUI()
m_pPointTable->setAlternatingRowColors(true);
pointLayout->addWidget(m_pPointTable, 1);
- // 测点列表管理按钮
QHBoxLayout* pointButtonLayout = new QHBoxLayout;
pointButtonLayout->addStretch();
m_pDeletePointButton = new QPushButton(interpolationText("Delete Selected"), pointGroup);
@@ -110,9 +239,19 @@ void nmWxPropertyInterpolationDlg::initInterpolationUI()
m_pClearPointsButton->setEnabled(false);
pointButtonLayout->addWidget(m_pClearPointsButton);
pointLayout->addLayout(pointButtonLayout);
+
+ QHBoxLayout* displayLayout = new QHBoxLayout;
+ m_pShowPointsCheck = new QCheckBox(interpolationText("Show measurement points"), pointGroup);
+ m_pShowPointsCheck->setChecked(true);
+ displayLayout->addWidget(m_pShowPointsCheck);
+ m_pShowLabelsCheck = new QCheckBox(interpolationText("Show labels"), pointGroup);
+ m_pShowLabelsCheck->setChecked(true);
+ displayLayout->addWidget(m_pShowLabelsCheck);
+ displayLayout->addStretch();
+ pointLayout->addLayout(displayLayout);
mainLayout->addWidget(pointGroup, 1);
- // Kriging插值参数设置
+ // Kriging插值参数设置.
QGroupBox* parameterGroup = new QGroupBox(interpolationText("Kriging Parameters"), this);
QFormLayout* parameterLayout = new QFormLayout(parameterGroup);
m_pNuggetSpin = createNumberSpinBox(parameterGroup, 0.01);
@@ -128,10 +267,9 @@ void nmWxPropertyInterpolationDlg::initInterpolationUI()
parameterLayout->addRow(interpolationText("Model:"), m_pModelCombo);
mainLayout->addWidget(parameterGroup);
- // 底部操作按钮
+ // 底部操作按钮.
QHBoxLayout* buttonLayout = new QHBoxLayout;
m_pPreviewButton = new QPushButton(interpolationText("Preview"), this);
- // 插值计算和预览功能将在后续阶段接入
m_pPreviewButton->setEnabled(false);
buttonLayout->addWidget(m_pPreviewButton);
buttonLayout->addStretch();
@@ -142,5 +280,640 @@ void nmWxPropertyInterpolationDlg::initInterpolationUI()
buttonLayout->addWidget(closeButton);
mainLayout->addLayout(buttonLayout);
+ connect(m_pDataSetCombo, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(onDataSetChanged(int)));
+ connect(m_pAddDataSetButton, SIGNAL(clicked()), this, SLOT(onAddDataSet()));
+ connect(m_pDeleteDataSetButton, SIGNAL(clicked()), this, SLOT(onDeleteDataSet()));
+ connect(m_pNameEdit, SIGNAL(textChanged(QString)),
+ this, SLOT(onDataSetNameChanged(QString)));
+ connect(m_pPropertyCombo, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(onCurrentDataSetEdited()));
+ connect(m_pNuggetSpin, SIGNAL(valueChanged(double)),
+ this, SLOT(onCurrentDataSetEdited()));
+ connect(m_pSillSpin, SIGNAL(valueChanged(double)),
+ this, SLOT(onCurrentDataSetEdited()));
+ connect(m_pRangeSpin, SIGNAL(valueChanged(double)),
+ this, SLOT(onCurrentDataSetEdited()));
+ connect(m_pModelCombo, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(onCurrentDataSetEdited()));
+ connect(m_pMapPickButton, SIGNAL(toggled(bool)), this, SLOT(onMapPickToggled(bool)));
+ connect(m_pPointTable, SIGNAL(itemSelectionChanged()),
+ this, SLOT(onPointSelectionChanged()));
+ connect(m_pPointTable, SIGNAL(itemChanged(QTableWidgetItem*)),
+ this, SLOT(onPointItemChanged(QTableWidgetItem*)));
+ connect(m_pDeletePointButton, SIGNAL(clicked()), this, SLOT(onDeleteSelectedPoint()));
+ connect(m_pClearPointsButton, SIGNAL(clicked()), this, SLOT(onClearPoints()));
+ connect(m_pShowPointsCheck, SIGNAL(toggled(bool)), this, SLOT(onShowPointsToggled(bool)));
+ connect(m_pShowLabelsCheck, SIGNAL(toggled(bool)), this, SLOT(onShowLabelsToggled(bool)));
connect(closeButton, SIGNAL(clicked()), this, SLOT(close()));
}
+
+void nmWxPropertyInterpolationDlg::initializeDataSets()
+{
+ m_bUpdatingUi = true;
+
+ if(!m_pDataManager.isNull()) {
+ m_vecDataSets = m_pDataManager->getPropertyInterpolationDataSets();
+ }
+
+ bool dataChanged = false;
+ for(int i = 0; i < m_vecDataSets.size(); ++i) {
+ if(m_vecDataSets[i].name.isEmpty()) {
+ m_vecDataSets[i].name = nextDataSetName();
+ dataChanged = true;
+ }
+ }
+
+ m_vecMarkerNames.resize(m_vecDataSets.size());
+ createMarkersForAllDataSets();
+
+ bool oldBlock = m_pDataSetCombo->blockSignals(true);
+ m_pDataSetCombo->clear();
+ for(int i = 0; i < m_vecDataSets.size(); ++i) {
+ m_pDataSetCombo->addItem(m_vecDataSets[i].name);
+ }
+ const int initialIndex = m_vecDataSets.isEmpty() ? -1 : 0;
+ m_pDataSetCombo->setCurrentIndex(initialIndex);
+ m_pDataSetCombo->blockSignals(oldBlock);
+
+ m_nCurrentDataSetIndex = initialIndex;
+ loadDataSet(initialIndex);
+ m_bUpdatingUi = false;
+ updateDataSetButtons();
+
+ if(dataChanged) {
+ syncDataSetsToManager(false);
+ }
+}
+
+nmPropertyInterpolationDataSet nmWxPropertyInterpolationDlg::createDefaultDataSet()
+{
+ nmPropertyInterpolationDataSet dataSet;
+ dataSet.name = nextDataSetName();
+ dataSet.property = "k";
+ dataSet.showPoints = true;
+ dataSet.showLabels = true;
+ dataSet.nugget = 0.01;
+ dataSet.sill = 100.0;
+ dataSet.range = 1000.0;
+ dataSet.model = 0;
+ return dataSet;
+}
+
+QString nmWxPropertyInterpolationDlg::nextDataSetName()
+{
+ for(int number = 1; ; ++number) {
+ const QString name = interpolationText("Dataset #%1").arg(number);
+ bool exists = false;
+ for(int i = 0; i < m_vecDataSets.size(); ++i) {
+ if(m_vecDataSets[i].name == name) {
+ exists = true;
+ break;
+ }
+ }
+
+ if(!exists) {
+ return name;
+ }
+ }
+}
+
+void nmWxPropertyInterpolationDlg::loadDataSet(int index)
+{
+ if(index < 0 || index >= m_vecDataSets.size()) {
+ clearCurrentDataSet();
+ return;
+ }
+
+ bool wasUpdating = m_bUpdatingUi;
+ m_bUpdatingUi = true;
+ const nmPropertyInterpolationDataSet& dataSet = m_vecDataSets[index];
+
+ m_pNameEdit->setText(dataSet.name);
+ int propertyIndex = m_pPropertyCombo->findData(dataSet.property);
+ m_pPropertyCombo->setCurrentIndex(propertyIndex < 0 ? 0 : propertyIndex);
+ m_pNuggetSpin->setValue(dataSet.nugget);
+ m_pSillSpin->setValue(dataSet.sill);
+ m_pRangeSpin->setValue(dataSet.range);
+ int modelIndex = m_pModelCombo->findData(dataSet.model);
+ m_pModelCombo->setCurrentIndex(modelIndex < 0 ? 0 : modelIndex);
+ m_pShowPointsCheck->setChecked(dataSet.showPoints);
+ m_pShowLabelsCheck->setChecked(dataSet.showLabels);
+
+ bool oldTableBlock = m_pPointTable->blockSignals(true);
+ m_pPointTable->setRowCount(0);
+ const QStringList markerNames = m_vecMarkerNames.value(index);
+ for(int i = 0; i < dataSet.points.size(); ++i) {
+ appendPointRow(dataSet.points[i], markerNames.value(i));
+ }
+ m_pPointTable->blockSignals(oldTableBlock);
+
+ clearTableSelection();
+ updatePointButtons();
+ updateCurrentMarkerVisibility();
+ m_bUpdatingUi = wasUpdating;
+ updateDataSetButtons();
+}
+
+void nmWxPropertyInterpolationDlg::clearCurrentDataSet()
+{
+ bool wasUpdating = m_bUpdatingUi;
+ m_bUpdatingUi = true;
+
+ if(m_pMapPickButton->isChecked()) {
+ m_pMapPickButton->setChecked(false);
+ }
+ m_pNameEdit->clear();
+ m_pPropertyCombo->setCurrentIndex(-1);
+ m_pNewValueSpin->setValue(0.0);
+ m_pPointTable->setRowCount(0);
+ m_pShowPointsCheck->setChecked(false);
+ m_pShowLabelsCheck->setChecked(false);
+ m_pNuggetSpin->setValue(0.01);
+ m_pSillSpin->setValue(100.0);
+ m_pRangeSpin->setValue(1000.0);
+ m_pModelCombo->setCurrentIndex(-1);
+
+ clearTableSelection();
+ m_bUpdatingUi = wasUpdating;
+ updateDataSetButtons();
+}
+
+void nmWxPropertyInterpolationDlg::saveCurrentDataSet()
+{
+ if(m_nCurrentDataSetIndex < 0 ||
+ m_nCurrentDataSetIndex >= m_vecDataSets.size()) {
+ return;
+ }
+
+ nmPropertyInterpolationDataSet& dataSet = m_vecDataSets[m_nCurrentDataSetIndex];
+ dataSet.name = m_pNameEdit->text();
+ dataSet.property = m_pPropertyCombo->itemData(m_pPropertyCombo->currentIndex()).toString();
+ dataSet.nugget = m_pNuggetSpin->value();
+ dataSet.sill = m_pSillSpin->value();
+ dataSet.range = m_pRangeSpin->value();
+ dataSet.model = m_pModelCombo->itemData(m_pModelCombo->currentIndex()).toInt();
+ dataSet.showPoints = m_pShowPointsCheck->isChecked();
+ dataSet.showLabels = m_pShowLabelsCheck->isChecked();
+
+}
+
+void nmWxPropertyInterpolationDlg::syncDataSetsToManager(bool markModified)
+{
+ if(!m_pDataManager.isNull()) {
+ m_pDataManager->setPropertyInterpolationDataSets(m_vecDataSets);
+ }
+
+ if(markModified && !m_pPlot.isNull()) {
+ m_pPlot->setModified(true);
+ }
+}
+
+void nmWxPropertyInterpolationDlg::updateDataSetButtons()
+{
+ const bool hasCurrent = m_nCurrentDataSetIndex >= 0 &&
+ m_nCurrentDataSetIndex < m_vecDataSets.size();
+ const bool canPickOnMap = hasCurrent && !m_pPlot.isNull() &&
+ m_pPlot->m_pPlotView != NULL && m_pPlot->m_pPlot != NULL;
+
+ m_pDataSetCombo->setEnabled(hasCurrent);
+ m_pDeleteDataSetButton->setEnabled(hasCurrent);
+ m_pNameEdit->setEnabled(hasCurrent);
+ m_pPropertyCombo->setEnabled(hasCurrent);
+ m_pNewValueSpin->setEnabled(hasCurrent);
+ m_pMapPickButton->setEnabled(canPickOnMap);
+ m_pPointTable->setEnabled(hasCurrent);
+ m_pShowPointsCheck->setEnabled(hasCurrent);
+ m_pShowLabelsCheck->setEnabled(hasCurrent);
+ m_pNuggetSpin->setEnabled(hasCurrent);
+ m_pSillSpin->setEnabled(hasCurrent);
+ m_pRangeSpin->setEnabled(hasCurrent);
+ m_pModelCombo->setEnabled(hasCurrent);
+ updatePointButtons();
+}
+
+void nmWxPropertyInterpolationDlg::onDataSetChanged(int index)
+{
+ if(m_bUpdatingUi || index < 0 || index >= m_vecDataSets.size() ||
+ index == m_nCurrentDataSetIndex) {
+ return;
+ }
+
+ saveCurrentDataSet();
+ syncDataSetsToManager(false);
+ m_nCurrentDataSetIndex = index;
+ loadDataSet(index);
+}
+
+void nmWxPropertyInterpolationDlg::onAddDataSet()
+{
+ saveCurrentDataSet();
+ m_vecDataSets.append(createDefaultDataSet());
+ m_vecMarkerNames.append(QStringList());
+
+ int newIndex = m_vecDataSets.size() - 1;
+ bool oldBlock = m_pDataSetCombo->blockSignals(true);
+ m_pDataSetCombo->addItem(m_vecDataSets[newIndex].name);
+ m_pDataSetCombo->setCurrentIndex(newIndex);
+ m_pDataSetCombo->blockSignals(oldBlock);
+
+ m_nCurrentDataSetIndex = newIndex;
+ loadDataSet(newIndex);
+ updateDataSetButtons();
+ syncDataSetsToManager(true);
+}
+
+void nmWxPropertyInterpolationDlg::onDeleteDataSet()
+{
+ if(m_nCurrentDataSetIndex < 0 ||
+ m_nCurrentDataSetIndex >= m_vecDataSets.size()) {
+ return;
+ }
+
+ int removedIndex = m_nCurrentDataSetIndex;
+ removeDataSetMarkers(removedIndex);
+ m_vecDataSets.remove(removedIndex);
+ m_vecMarkerNames.remove(removedIndex);
+
+ const int newIndex = m_vecDataSets.isEmpty() ? -1 :
+ qMin(removedIndex, m_vecDataSets.size() - 1);
+ bool oldBlock = m_pDataSetCombo->blockSignals(true);
+ m_pDataSetCombo->removeItem(removedIndex);
+ m_pDataSetCombo->setCurrentIndex(newIndex);
+ m_pDataSetCombo->blockSignals(oldBlock);
+
+ m_nCurrentDataSetIndex = newIndex;
+ loadDataSet(newIndex);
+ updateDataSetButtons();
+ syncDataSetsToManager(true);
+}
+
+void nmWxPropertyInterpolationDlg::onDataSetNameChanged(const QString& name)
+{
+ if(m_bUpdatingUi || m_nCurrentDataSetIndex < 0 ||
+ m_nCurrentDataSetIndex >= m_vecDataSets.size()) {
+ return;
+ }
+
+ m_vecDataSets[m_nCurrentDataSetIndex].name = name;
+ m_pDataSetCombo->setItemText(m_nCurrentDataSetIndex, name);
+ syncDataSetsToManager(true);
+}
+
+void nmWxPropertyInterpolationDlg::onCurrentDataSetEdited()
+{
+ if(m_bUpdatingUi) {
+ return;
+ }
+
+ saveCurrentDataSet();
+ syncDataSetsToManager(true);
+}
+
+bool nmWxPropertyInterpolationDlg::eventFilter(QObject* watched, QEvent* event)
+{
+ if(event != NULL && event->type() == QEvent::MouseButtonPress && m_pPointTable != NULL) {
+ QWidget* clickedWidget = qobject_cast(watched);
+
+ if(clickedWidget != NULL) {
+ bool isTableViewport = clickedWidget == m_pPointTable->viewport() ||
+ m_pPointTable->viewport()->isAncestorOf(clickedWidget);
+
+ if(clickedWidget == m_pPointTable->viewport()) {
+ QMouseEvent* mouseEvent = static_cast(event);
+
+ if(m_pPointTable->itemAt(mouseEvent->pos()) == NULL) {
+ clearTableSelection();
+ }
+ } else if(!isTableViewport && clickedWidget != m_pDeletePointButton) {
+ clearTableSelection();
+ }
+ }
+ }
+
+ return iDlgBase::eventFilter(watched, event);
+}
+
+void nmWxPropertyInterpolationDlg::onMapPickToggled(bool checked)
+{
+ if(m_pPlot.isNull() || m_pPlot->m_pPlotView == NULL) {
+ return;
+ }
+
+ disconnect(m_pPlot->m_pPlotView, SIGNAL(sigLeftClick(QPointF)),
+ this, SLOT(onMapClicked(QPointF)));
+
+ if(checked) {
+ m_pPlot->cancelActiveTools();
+ connect(m_pPlot->m_pPlotView, SIGNAL(sigLeftClick(QPointF)),
+ this, SLOT(onMapClicked(QPointF)));
+ m_pPlot->m_pPlotView->setCursor(Qt::CrossCursor);
+ } else {
+ m_pPlot->m_pPlotView->restoreCursor();
+ }
+}
+
+void nmWxPropertyInterpolationDlg::onMapClicked(const QPointF& position)
+{
+ if(!m_pMapPickButton->isChecked() || m_pPlot.isNull() ||
+ m_pPlot->m_pPlot == NULL || m_nCurrentDataSetIndex < 0) {
+ return;
+ }
+
+ if(!m_pPlot->m_pPlot->getInnerRectF().contains(position)) {
+ return;
+ }
+
+ QPointF plotPosition = position;
+ QPointF valuePoint = m_pPlot->m_pPlot->getValueForPos(plotPosition);
+ appendPoint(valuePoint);
+}
+
+void nmWxPropertyInterpolationDlg::appendPoint(const QPointF& valuePoint)
+{
+ if(m_nCurrentDataSetIndex < 0 ||
+ m_nCurrentDataSetIndex >= m_vecDataSets.size()) {
+ return;
+ }
+
+ nmPropertyInterpolationDataSet& dataSet = m_vecDataSets[m_nCurrentDataSetIndex];
+ double pointValue = m_pNewValueSpin->value();
+ nmPropertyInterpolationPointData point(valuePoint.x(), valuePoint.y(), pointValue);
+ QString markerName = createMarker(valuePoint, pointValue,
+ dataSet.showPoints, dataSet.showLabels);
+
+ dataSet.points.append(point);
+ m_vecMarkerNames[m_nCurrentDataSetIndex].append(markerName);
+
+ bool oldBlock = m_pPointTable->blockSignals(true);
+ appendPointRow(point, markerName);
+ m_pPointTable->blockSignals(oldBlock);
+ m_pPointTable->scrollToBottom();
+ updatePointButtons();
+ syncDataSetsToManager(true);
+}
+
+void nmWxPropertyInterpolationDlg::appendPointRow(
+ const nmPropertyInterpolationPointData& point,
+ const QString& markerName)
+{
+ int row = m_pPointTable->rowCount();
+ m_pPointTable->insertRow(row);
+
+ QTableWidgetItem* xItem = new QTableWidgetItem(QString::number(point.x, 'g', 15));
+ xItem->setFlags(xItem->flags() & ~Qt::ItemIsEditable);
+ xItem->setData(Qt::UserRole, markerName);
+ m_pPointTable->setItem(row, 0, xItem);
+
+ QTableWidgetItem* yItem = new QTableWidgetItem(QString::number(point.y, 'g', 15));
+ yItem->setFlags(yItem->flags() & ~Qt::ItemIsEditable);
+ m_pPointTable->setItem(row, 1, yItem);
+
+ m_pPointTable->setItem(row, 2,
+ new QTableWidgetItem(QString::number(point.value, 'f', 6)));
+}
+
+QString nmWxPropertyInterpolationDlg::createMarker(const QPointF& valuePosition,
+ double value,
+ bool showPoints,
+ bool showLabels)
+{
+ if(m_pPlot.isNull() || m_pPlot->m_pPlot == NULL) {
+ return QString();
+ }
+
+ QString markerName;
+ do {
+ markerName = QString("__PropertyInterpolationPoint_%1").arg(++m_nNextPointId);
+ } while(m_pPlot->m_pPlot->getObjByName(markerName) != NULL);
+
+ bool wasModified = m_pPlot->isModified();
+ PropertyInterpolationMarker* marker = new PropertyInterpolationMarker(
+ markerName,
+ m_pPlot->m_pPlot->getMainAxisX(),
+ m_pPlot->m_pPlot->getMainAxisY());
+ m_pPlot->bindObjSignals(marker);
+
+ if(!m_pPlot->m_pPlot->addOneObj(marker)) {
+ delete marker;
+ m_pPlot->setModified(wasModified);
+ return QString();
+ }
+
+ QVector values;
+ values.append(valuePosition);
+ marker->setAllValues(values);
+ m_pPlot->slotObjCompleted(marker);
+ setMarkerLabel(marker, QString::number(value, 'g', 10));
+ marker->setReadOnly(true);
+ marker->setLockPos(true);
+ marker->showSubObjs(showPoints && showLabels);
+ marker->setVisible(showPoints);
+ marker->deselect(true);
+ marker->update();
+ m_pPlot->setModified(wasModified);
+ return markerName;
+}
+
+void nmWxPropertyInterpolationDlg::createMarkersForAllDataSets()
+{
+ if(m_pPlot.isNull() || m_pPlot->m_pPlot == NULL) {
+ return;
+ }
+
+ for(int dataSetIndex = 0; dataSetIndex < m_vecDataSets.size(); ++dataSetIndex) {
+ const nmPropertyInterpolationDataSet& dataSet = m_vecDataSets[dataSetIndex];
+ QStringList markerNames;
+
+ for(int pointIndex = 0; pointIndex < dataSet.points.size(); ++pointIndex) {
+ const nmPropertyInterpolationPointData& point = dataSet.points[pointIndex];
+ QPointF valuePosition(point.x, point.y);
+ markerNames.append(createMarker(valuePosition, point.value,
+ dataSet.showPoints, dataSet.showLabels));
+ }
+
+ m_vecMarkerNames[dataSetIndex] = markerNames;
+ }
+}
+
+void nmWxPropertyInterpolationDlg::removeDataSetMarkers(int dataSetIndex)
+{
+ if(dataSetIndex < 0 || dataSetIndex >= m_vecMarkerNames.size()) {
+ return;
+ }
+
+ const QStringList markerNames = m_vecMarkerNames[dataSetIndex];
+ for(int i = 0; i < markerNames.size(); ++i) {
+ removeMarkerByName(markerNames[i]);
+ }
+ m_vecMarkerNames[dataSetIndex].clear();
+}
+
+void nmWxPropertyInterpolationDlg::removeAllMarkers()
+{
+ for(int i = 0; i < m_vecMarkerNames.size(); ++i) {
+ removeDataSetMarkers(i);
+ }
+ m_vecMarkerNames.clear();
+}
+
+QString nmWxPropertyInterpolationDlg::markerNameAt(int row) const
+{
+ if(m_pPointTable == NULL || row < 0 || row >= m_pPointTable->rowCount()) {
+ return QString();
+ }
+
+ QTableWidgetItem* item = m_pPointTable->item(row, 0);
+ return item == NULL ? QString() : item->data(Qt::UserRole).toString();
+}
+
+nmObjPoint* nmWxPropertyInterpolationDlg::markerByName(const QString& markerName) const
+{
+ if(m_pPlot.isNull() || m_pPlot->m_pPlot == NULL || markerName.isEmpty()) {
+ return NULL;
+ }
+
+ return dynamic_cast(m_pPlot->m_pPlot->getObjByName(markerName));
+}
+
+nmObjPoint* nmWxPropertyInterpolationDlg::markerAt(int row) const
+{
+ return markerByName(markerNameAt(row));
+}
+
+void nmWxPropertyInterpolationDlg::removeMarkerByName(const QString& markerName)
+{
+ if(m_pPlot.isNull() || m_pPlot->m_pPlot == NULL || markerName.isEmpty() ||
+ m_pPlot->m_pPlot->getObjByName(markerName) == NULL) {
+ return;
+ }
+
+ bool wasModified = m_pPlot->isModified();
+ m_pPlot->m_pPlot->removeObjByName(markerName);
+ m_pPlot->setModified(wasModified);
+}
+
+void nmWxPropertyInterpolationDlg::onPointSelectionChanged()
+{
+ updatePointButtons();
+}
+
+void nmWxPropertyInterpolationDlg::onPointItemChanged(QTableWidgetItem* item)
+{
+ if(m_bUpdatingUi || item == NULL || item->column() != 2 ||
+ m_nCurrentDataSetIndex < 0 ||
+ m_nCurrentDataSetIndex >= m_vecDataSets.size() ||
+ item->row() >= m_vecDataSets[m_nCurrentDataSetIndex].points.size()) {
+ return;
+ }
+
+ m_vecDataSets[m_nCurrentDataSetIndex].points[item->row()].value = item->text().toDouble();
+ nmObjPoint* marker = markerAt(item->row());
+ if(marker != NULL) {
+ setMarkerLabel(marker, item->text());
+ marker->update();
+ }
+ syncDataSetsToManager(true);
+}
+
+void nmWxPropertyInterpolationDlg::onDeleteSelectedPoint()
+{
+ int row = m_pPointTable->currentRow();
+ if(row < 0 || m_nCurrentDataSetIndex < 0 ||
+ m_nCurrentDataSetIndex >= m_vecDataSets.size()) {
+ return;
+ }
+
+ removeMarkerByName(markerNameAt(row));
+ if(row < m_vecDataSets[m_nCurrentDataSetIndex].points.size()) {
+ m_vecDataSets[m_nCurrentDataSetIndex].points.remove(row);
+ }
+ if(row < m_vecMarkerNames[m_nCurrentDataSetIndex].size()) {
+ m_vecMarkerNames[m_nCurrentDataSetIndex].removeAt(row);
+ }
+ m_pPointTable->removeRow(row);
+ clearTableSelection();
+ updatePointButtons();
+ syncDataSetsToManager(true);
+}
+
+void nmWxPropertyInterpolationDlg::onClearPoints()
+{
+ if(m_nCurrentDataSetIndex < 0 ||
+ m_nCurrentDataSetIndex >= m_vecDataSets.size()) {
+ return;
+ }
+
+ removeDataSetMarkers(m_nCurrentDataSetIndex);
+ m_vecDataSets[m_nCurrentDataSetIndex].points.clear();
+ m_pPointTable->setRowCount(0);
+ clearTableSelection();
+ updatePointButtons();
+ syncDataSetsToManager(true);
+}
+
+void nmWxPropertyInterpolationDlg::onShowPointsToggled(bool checked)
+{
+ if(m_bUpdatingUi || m_nCurrentDataSetIndex < 0 ||
+ m_nCurrentDataSetIndex >= m_vecDataSets.size()) {
+ return;
+ }
+
+ m_vecDataSets[m_nCurrentDataSetIndex].showPoints = checked;
+ updateCurrentMarkerVisibility();
+ syncDataSetsToManager(true);
+}
+
+void nmWxPropertyInterpolationDlg::onShowLabelsToggled(bool checked)
+{
+ if(m_bUpdatingUi || m_nCurrentDataSetIndex < 0 ||
+ m_nCurrentDataSetIndex >= m_vecDataSets.size()) {
+ return;
+ }
+
+ m_vecDataSets[m_nCurrentDataSetIndex].showLabels = checked;
+ updateCurrentMarkerVisibility();
+ syncDataSetsToManager(true);
+}
+
+void nmWxPropertyInterpolationDlg::clearTableSelection()
+{
+ m_pPointTable->clearSelection();
+ m_pPointTable->setCurrentCell(-1, -1);
+}
+
+void nmWxPropertyInterpolationDlg::updatePointButtons()
+{
+ const bool hasCurrent = m_nCurrentDataSetIndex >= 0 &&
+ m_nCurrentDataSetIndex < m_vecDataSets.size();
+ m_pDeletePointButton->setEnabled(hasCurrent && m_pPointTable->currentRow() >= 0);
+ m_pClearPointsButton->setEnabled(hasCurrent && m_pPointTable->rowCount() > 0);
+}
+
+void nmWxPropertyInterpolationDlg::updateCurrentMarkerVisibility()
+{
+ // 地图上只显示当前数据组的测点,其他数据组统一隐藏.
+ for(int dataSetIndex = 0;
+ dataSetIndex < m_vecMarkerNames.size(); ++dataSetIndex) {
+ const bool isCurrentDataSet = dataSetIndex == m_nCurrentDataSetIndex &&
+ dataSetIndex < m_vecDataSets.size();
+ const bool showPoints = isCurrentDataSet &&
+ m_vecDataSets[dataSetIndex].showPoints;
+ const bool showLabels = showPoints &&
+ m_vecDataSets[dataSetIndex].showLabels;
+ const QStringList markerNames = m_vecMarkerNames[dataSetIndex];
+
+ for(int markerIndex = 0; markerIndex < markerNames.size(); ++markerIndex) {
+ nmObjPoint* marker = markerByName(markerNames[markerIndex]);
+ if(marker != NULL) {
+ marker->setVisible(showPoints);
+ marker->showSubObjs(showLabels);
+ marker->update();
+ }
+ }
+ }
+
+ if(!m_pPlot.isNull() && m_pPlot->m_pPlotView != NULL) {
+ m_pPlot->m_pPlotView->updateViewport();
+ }
+}