diff --git a/Bin/Config/Lang/cn/nmNum_cn.qm b/Bin/Config/Lang/cn/nmNum_cn.qm index 24a0ac6..abc015a 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 50089c7..0eb1ffe 100644 --- a/Bin/Config/Lang/cn/nmNum_cn.ts +++ b/Bin/Config/Lang/cn/nmNum_cn.ts @@ -6578,6 +6578,10 @@ Average pressure in contour: %2 MPa Permeability k 渗透率 k + + Permeability k (mD) + 渗透率 k(mD) + Porosity phi 孔隙度 phi @@ -6586,6 +6590,10 @@ Average pressure in contour: %2 MPa Reservoir thickness h 储层厚度 h + + Reservoir thickness h (m) + 储层厚度 h(m) + Name: 名称: @@ -6666,6 +6674,10 @@ Average pressure in contour: %2 MPa Gaussian (2) 高斯模型(2) + + Use Interpolation in Solver + 求解时使用插值 + Preview 预览 diff --git a/Include/nmNum/nmSubWxs/nmWxPropertyInterpolationDlg.h b/Include/nmNum/nmSubWxs/nmWxPropertyInterpolationDlg.h index 2fd866f..0053cf2 100644 --- a/Include/nmNum/nmSubWxs/nmWxPropertyInterpolationDlg.h +++ b/Include/nmNum/nmSubWxs/nmWxPropertyInterpolationDlg.h @@ -41,7 +41,15 @@ private slots: void onAddDataSet(); void onDeleteDataSet(); void onDataSetNameChanged(const QString& name); + // 当前数据组属性及显示单位变化. + void onCurrentDataSetPropertyChanged(); void onCurrentDataSetEdited(); + void onXDisplayUnitChanged(const QString& unit); + void onYDisplayUnitChanged(const QString& unit); + void onValueDisplayUnitChanged(const QString& unit); + void onRangeDisplayUnitChanged(const QString& unit); + // 正式求解使用的数据组变化. + void onCalculationSelectionChanged(); void onMapPickToggled(bool checked); void onMapClicked(const QPointF& position); void onPointSelectionChanged(); @@ -62,8 +70,20 @@ private: void loadDataSet(int index); void clearCurrentDataSet(); void saveCurrentDataSet(); + // 单位控件只维护界面显示状态;插值数据始终按求解器基准单位保存. + void updateUnitControls(nmPropertyInterpolationDataSet& dataSet); + void updatePointDisplayValues(); + void clearPointRows(); void syncDataSetsToManager(bool markModified); void updateDataSetButtons(); + // 管理正式求解时k、phi和h各自使用的插值数据组. + void updateCalculationDataSetControls(); + void updateCalculationDataSetControl(const QString& property, + QCheckBox* checkBox, + QComboBox* comboBox); + void saveCalculationSelection(const QString& property, + QCheckBox* checkBox, + QComboBox* comboBox); // 管理测点表格和地图上的临时标记. void appendPoint(const QPointF& valuePoint); @@ -109,8 +129,14 @@ private: // 测点数据录入. QDoubleSpinBox* m_pNewValueSpin; + // 新值单位与表格Value列单位保持同步. + QComboBox* m_pNewValueUnitCombo; QPushButton* m_pMapPickButton; QTableWidget* m_pPointTable; + // 表格第0行中的X、Y和Value显示单位. + QComboBox* m_pXUnitCombo; + QComboBox* m_pYUnitCombo; + QComboBox* m_pValueUnitCombo; QPushButton* m_pDeletePointButton; QPushButton* m_pClearPointsButton; QCheckBox* m_pShowPointsCheck; @@ -120,8 +146,17 @@ private: QDoubleSpinBox* m_pNuggetSpin; QDoubleSpinBox* m_pSillSpin; QDoubleSpinBox* m_pRangeSpin; + QComboBox* m_pRangeUnitCombo; QComboBox* m_pModelCombo; + // 正式求解时各属性使用的数据组. + QCheckBox* m_pUseKCheck; + QComboBox* m_pKCalculationDataSetCombo; + QCheckBox* m_pUsePhiCheck; + QComboBox* m_pPhiCalculationDataSetCombo; + QCheckBox* m_pUseHCheck; + QComboBox* m_pHCalculationDataSetCombo; + // 结果预览及应用. QPushButton* m_pPreviewButton; QPushButton* m_pApplyButton; diff --git a/Src/nmNum/nmSubWxs/nmWxPropertyInterpolationDlg.cpp b/Src/nmNum/nmSubWxs/nmWxPropertyInterpolationDlg.cpp index 2f9ecfc..44d4571 100644 --- a/Src/nmNum/nmSubWxs/nmWxPropertyInterpolationDlg.cpp +++ b/Src/nmNum/nmSubWxs/nmWxPropertyInterpolationDlg.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,7 @@ #include #include #include +#include #include #include "nmCalculationUtils.h" @@ -32,12 +34,22 @@ #include "nmGuiPlot.h" #include "nmObjPoint.h" #include "nmWxPropertyInterpolationPreviewDlg.h" +#include "iUnitGroup.h" +#include "iUnitHelper.h" #include "tCurvePlotView.h" #include "ZxObjText.h" #include "ZxPlot.h" namespace { +// 表格第0行保留给单位,实际测点从第1行开始. +const int POINT_UNIT_ROW = 0; +const int FIRST_POINT_ROW = 1; +// 坐标和厚度以m保存,渗透率以D保存但默认使用mD显示. +const char* LENGTH_BASE_UNIT = "m"; +const char* PERMEABILITY_BASE_UNIT = "D"; +const char* PERMEABILITY_DISPLAY_UNIT = "mD"; + // 使用独立翻译上下文,便于统一维护对话框文本. QString interpolationText(const char* sourceText) { @@ -55,6 +67,133 @@ QDoubleSpinBox* createNumberSpinBox(QWidget* parent, double value) return spinBox; } +QString propertyBaseUnit(const QString& property) +{ + // 孔隙度为无量纲量,返回空单位后界面会禁用对应单位下拉框. + if(property == "k") { + return PERMEABILITY_BASE_UNIT; + } + if(property == "h") { + return LENGTH_BASE_UNIT; + } + return QString(); +} + +QString defaultPropertyDisplayUnit(const QString& property) +{ + // 渗透率采用工程中常用的mD显示,其余属性默认显示基准单位. + if(property == "k") { + return PERMEABILITY_DISPLAY_UNIT; + } + return propertyBaseUnit(property); +} + +QString unitGroupLookupUnit(const QString& unit) +{ + // D与时间单位d仅大小写不同,使用唯一的mD定位渗透率单位组. + return unit == PERMEABILITY_BASE_UNIT ? + QString(PERMEABILITY_DISPLAY_UNIT) : unit; +} + +bool convertUnitValue(double sourceValue, + const QString& sourceUnit, + const QString& destinationUnit, + double& destinationValue) +{ + if(sourceUnit == destinationUnit || + (sourceUnit.isEmpty() && destinationUnit.isEmpty())) { + destinationValue = sourceValue; + return true; + } + if(sourceUnit.isEmpty() || destinationUnit.isEmpty()) { + return false; + } + + // 复用框架单位表完成换算,不在插值模块中维护独立换算系数. + iUnitGroup* unitGroup = iUnitHelper::getUnitGroupByUnit( + unitGroupLookupUnit(sourceUnit)); + if(unitGroup == NULL || unitGroup->indexOf(destinationUnit) < 0) { + return false; + } + + int digit = 6; + return unitGroup->convert(sourceUnit, sourceValue, + destinationUnit, destinationValue, digit); +} + +double convertedUnitValue(double sourceValue, + const QString& sourceUnit, + const QString& destinationUnit) +{ + double destinationValue = sourceValue; + convertUnitValue(sourceValue, sourceUnit, + destinationUnit, destinationValue); + return destinationValue; +} + +QString displayValueText(double value) +{ + // 表格使用较高有效位数,减少多次显示和回写造成的精度损失. + return QString::number(value, 'g', 15); +} + +void populateUnitCombo(QComboBox* comboBox, + const QString& baseUnit, + const QString& selectedUnit) +{ + if(comboBox == NULL) { + return; + } + + // 单位列表从全局单位表加载,屏蔽信号可避免初始化过程反向修改数据. + bool oldBlock = comboBox->blockSignals(true); + comboBox->clear(); + if(baseUnit.isEmpty()) { + comboBox->addItem(QString()); + comboBox->setCurrentIndex(0); + comboBox->setEnabled(false); + comboBox->blockSignals(oldBlock); + return; + } + + const QString lookupUnit = unitGroupLookupUnit(baseUnit); + QStringList units; + iUnitGroup* unitGroup = iUnitHelper::getUnitGroupByUnit(lookupUnit); + if(unitGroup != NULL) { + units = unitGroup->getAllUnitNames(); + } + if(units.isEmpty()) { + units.append(baseUnit); + } + comboBox->addItems(units); + + int selectedIndex = comboBox->findText(selectedUnit); + if(selectedIndex < 0) { + selectedIndex = comboBox->findText(lookupUnit); + } + if(selectedIndex < 0) { + selectedIndex = comboBox->findText(baseUnit); + } + comboBox->setCurrentIndex(selectedIndex < 0 ? 0 : selectedIndex); + comboBox->setEnabled(true); + comboBox->blockSignals(oldBlock); +} + +void setTableUnitComboStyle(QComboBox* comboBox) +{ + if(comboBox == NULL) { + return; + } + + // 仅借用可编辑模式调整文字对齐,输入区域仍设置为只读. + comboBox->setEditable(true); + comboBox->lineEdit()->setAlignment(Qt::AlignCenter); + comboBox->lineEdit()->setReadOnly(true); + comboBox->setStyleSheet( + "QComboBox { border: none; background: transparent; padding-left: 4px; }" + "QComboBox::drop-down { border: none; }"); +} + // 插值测点使用独立的小方块标记,避免与井图元混淆. class PropertyInterpolationMarker : public nmObjPoint { @@ -175,8 +314,12 @@ nmWxPropertyInterpolationDlg::nmWxPropertyInterpolationDlg( m_pPropertyCombo(NULL), m_pNameEdit(NULL), m_pNewValueSpin(NULL), + m_pNewValueUnitCombo(NULL), m_pMapPickButton(NULL), m_pPointTable(NULL), + m_pXUnitCombo(NULL), + m_pYUnitCombo(NULL), + m_pValueUnitCombo(NULL), m_pDeletePointButton(NULL), m_pClearPointsButton(NULL), m_pShowPointsCheck(NULL), @@ -184,7 +327,14 @@ nmWxPropertyInterpolationDlg::nmWxPropertyInterpolationDlg( m_pNuggetSpin(NULL), m_pSillSpin(NULL), m_pRangeSpin(NULL), + m_pRangeUnitCombo(NULL), m_pModelCombo(NULL), + m_pUseKCheck(NULL), + m_pKCalculationDataSetCombo(NULL), + m_pUsePhiCheck(NULL), + m_pPhiCalculationDataSetCombo(NULL), + m_pUseHCheck(NULL), + m_pHCalculationDataSetCombo(NULL), m_pPreviewButton(NULL), m_pApplyButton(NULL), m_pPreviewDialog(NULL), @@ -193,9 +343,10 @@ nmWxPropertyInterpolationDlg::nmWxPropertyInterpolationDlg( setWindowTitle(interpolationText("Property Interpolation")); setWindowModality(Qt::NonModal); setModal(false); - setMinimumSize(520, 620); - resize(560, 680); + setMinimumSize(520, 680); + resize(560, 740); + // 合并连续编辑触发的刷新,避免每次数值变化都立即重新插值. m_pPreviewRefreshTimer = new QTimer(this); m_pPreviewRefreshTimer->setSingleShot(true); m_pPreviewRefreshTimer->setInterval(200); @@ -270,6 +421,11 @@ void nmWxPropertyInterpolationDlg::initInterpolationUI() newPointLayout->addWidget(new QLabel(interpolationText("New value:"), pointGroup)); m_pNewValueSpin = createNumberSpinBox(pointGroup, 0.0); newPointLayout->addWidget(m_pNewValueSpin, 1); + m_pNewValueUnitCombo = new QComboBox(pointGroup); + m_pNewValueUnitCombo->setMinimumWidth(80); + populateUnitCombo(m_pNewValueUnitCombo, + PERMEABILITY_BASE_UNIT, PERMEABILITY_DISPLAY_UNIT); + newPointLayout->addWidget(m_pNewValueUnitCombo); m_pMapPickButton = new QPushButton(interpolationText("Select on Map"), pointGroup); m_pMapPickButton->setCheckable(true); m_pMapPickButton->setEnabled(!m_pPlot.isNull() && @@ -278,14 +434,31 @@ void nmWxPropertyInterpolationDlg::initInterpolationUI() newPointLayout->addWidget(m_pMapPickButton); pointLayout->addLayout(newPointLayout); - m_pPointTable = new QTableWidget(0, 3, pointGroup); + m_pPointTable = new QTableWidget(1, 3, pointGroup); QStringList headers; headers << interpolationText("X") << interpolationText("Y") << interpolationText("Value"); m_pPointTable->setHorizontalHeaderLabels(headers); + m_pPointTable->verticalHeader()->setVisible(false); m_pPointTable->horizontalHeader()->setResizeMode(QHeaderView::Stretch); m_pPointTable->setSelectionBehavior(QAbstractItemView::SelectRows); m_pPointTable->setSelectionMode(QAbstractItemView::SingleSelection); m_pPointTable->setAlternatingRowColors(true); + m_pPointTable->setRowHeight(POINT_UNIT_ROW, 24); + + // 第0行固定显示各列单位,数据行从第1行开始. + m_pXUnitCombo = new QComboBox(m_pPointTable); + m_pYUnitCombo = new QComboBox(m_pPointTable); + m_pValueUnitCombo = new QComboBox(m_pPointTable); + setTableUnitComboStyle(m_pXUnitCombo); + setTableUnitComboStyle(m_pYUnitCombo); + setTableUnitComboStyle(m_pValueUnitCombo); + populateUnitCombo(m_pXUnitCombo, LENGTH_BASE_UNIT, LENGTH_BASE_UNIT); + populateUnitCombo(m_pYUnitCombo, LENGTH_BASE_UNIT, LENGTH_BASE_UNIT); + populateUnitCombo(m_pValueUnitCombo, + PERMEABILITY_BASE_UNIT, PERMEABILITY_DISPLAY_UNIT); + m_pPointTable->setCellWidget(POINT_UNIT_ROW, 0, m_pXUnitCombo); + m_pPointTable->setCellWidget(POINT_UNIT_ROW, 1, m_pYUnitCombo); + m_pPointTable->setCellWidget(POINT_UNIT_ROW, 2, m_pValueUnitCombo); pointLayout->addWidget(m_pPointTable, 1); QHBoxLayout* pointButtonLayout = new QHBoxLayout; @@ -316,8 +489,17 @@ void nmWxPropertyInterpolationDlg::initInterpolationUI() parameterLayout->addRow(interpolationText("Nugget:"), m_pNuggetSpin); m_pSillSpin = createNumberSpinBox(parameterGroup, 100.0); parameterLayout->addRow(interpolationText("Sill:"), m_pSillSpin); + QWidget* rangeWidget = new QWidget(parameterGroup); + QHBoxLayout* rangeLayout = new QHBoxLayout(rangeWidget); + rangeLayout->setContentsMargins(0, 0, 0, 0); + rangeLayout->setSpacing(6); m_pRangeSpin = createNumberSpinBox(parameterGroup, 1000.0); - parameterLayout->addRow(interpolationText("Range:"), m_pRangeSpin); + rangeLayout->addWidget(m_pRangeSpin, 1); + m_pRangeUnitCombo = new QComboBox(parameterGroup); + m_pRangeUnitCombo->setMinimumWidth(80); + populateUnitCombo(m_pRangeUnitCombo, LENGTH_BASE_UNIT, LENGTH_BASE_UNIT); + rangeLayout->addWidget(m_pRangeUnitCombo); + parameterLayout->addRow(interpolationText("Range:"), rangeWidget); m_pModelCombo = new QComboBox(parameterGroup); m_pModelCombo->addItem(interpolationText("Spherical (0)"), 0); m_pModelCombo->addItem(interpolationText("Exponential (1)"), 1); @@ -325,6 +507,27 @@ void nmWxPropertyInterpolationDlg::initInterpolationUI() parameterLayout->addRow(interpolationText("Model:"), m_pModelCombo); mainLayout->addWidget(parameterGroup); + // 分别指定正式求解时需要使用插值结果的属性和数据组. + QGroupBox* calculationGroup = new QGroupBox( + interpolationText("Use Interpolation in Solver"), this); + QGridLayout* calculationLayout = new QGridLayout(calculationGroup); + m_pUseKCheck = new QCheckBox(interpolationText("Permeability k"), calculationGroup); + m_pKCalculationDataSetCombo = new QComboBox(calculationGroup); + calculationLayout->addWidget(m_pUseKCheck, 0, 0); + calculationLayout->addWidget(m_pKCalculationDataSetCombo, 0, 1); + + m_pUsePhiCheck = new QCheckBox(interpolationText("Porosity phi"), calculationGroup); + m_pPhiCalculationDataSetCombo = new QComboBox(calculationGroup); + calculationLayout->addWidget(m_pUsePhiCheck, 1, 0); + calculationLayout->addWidget(m_pPhiCalculationDataSetCombo, 1, 1); + + m_pUseHCheck = new QCheckBox(interpolationText("Reservoir thickness h"), calculationGroup); + m_pHCalculationDataSetCombo = new QComboBox(calculationGroup); + calculationLayout->addWidget(m_pUseHCheck, 2, 0); + calculationLayout->addWidget(m_pHCalculationDataSetCombo, 2, 1); + calculationLayout->setColumnStretch(1, 1); + mainLayout->addWidget(calculationGroup); + // 底部操作按钮. QHBoxLayout* buttonLayout = new QHBoxLayout; m_pPreviewButton = new QPushButton(interpolationText("Preview"), this); @@ -345,13 +548,23 @@ void nmWxPropertyInterpolationDlg::initInterpolationUI() connect(m_pNameEdit, SIGNAL(textChanged(QString)), this, SLOT(onDataSetNameChanged(QString))); connect(m_pPropertyCombo, SIGNAL(currentIndexChanged(int)), - this, SLOT(onCurrentDataSetEdited())); + this, SLOT(onCurrentDataSetPropertyChanged())); 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_pXUnitCombo, SIGNAL(currentIndexChanged(const QString&)), + this, SLOT(onXDisplayUnitChanged(const QString&))); + connect(m_pYUnitCombo, SIGNAL(currentIndexChanged(const QString&)), + this, SLOT(onYDisplayUnitChanged(const QString&))); + connect(m_pNewValueUnitCombo, SIGNAL(currentIndexChanged(const QString&)), + this, SLOT(onValueDisplayUnitChanged(const QString&))); + connect(m_pValueUnitCombo, SIGNAL(currentIndexChanged(const QString&)), + this, SLOT(onValueDisplayUnitChanged(const QString&))); + connect(m_pRangeUnitCombo, SIGNAL(currentIndexChanged(const QString&)), + this, SLOT(onRangeDisplayUnitChanged(const QString&))); connect(m_pModelCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onCurrentDataSetEdited())); connect(m_pMapPickButton, SIGNAL(toggled(bool)), this, SLOT(onMapPickToggled(bool))); @@ -363,6 +576,18 @@ void nmWxPropertyInterpolationDlg::initInterpolationUI() 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(m_pUseKCheck, SIGNAL(toggled(bool)), + this, SLOT(onCalculationSelectionChanged())); + connect(m_pKCalculationDataSetCombo, SIGNAL(currentIndexChanged(int)), + this, SLOT(onCalculationSelectionChanged())); + connect(m_pUsePhiCheck, SIGNAL(toggled(bool)), + this, SLOT(onCalculationSelectionChanged())); + connect(m_pPhiCalculationDataSetCombo, SIGNAL(currentIndexChanged(int)), + this, SLOT(onCalculationSelectionChanged())); + connect(m_pUseHCheck, SIGNAL(toggled(bool)), + this, SLOT(onCalculationSelectionChanged())); + connect(m_pHCalculationDataSetCombo, SIGNAL(currentIndexChanged(int)), + this, SLOT(onCalculationSelectionChanged())); connect(m_pPreviewButton, SIGNAL(clicked()), this, SLOT(onPreview())); connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); } @@ -371,6 +596,7 @@ void nmWxPropertyInterpolationDlg::initializeDataSets() { m_bUpdatingUi = true; + // 数据组允许为空,首次进入窗口时不自动创建默认数据组. if(!m_pDataManager.isNull()) { m_vecDataSets = m_pDataManager->getPropertyInterpolationDataSets(); } @@ -400,6 +626,7 @@ void nmWxPropertyInterpolationDlg::initializeDataSets() loadDataSet(initialIndex); m_bUpdatingUi = false; updateDataSetButtons(); + updateCalculationDataSetControls(); if(dataChanged) { syncDataSetsToManager(false); @@ -448,26 +675,33 @@ void nmWxPropertyInterpolationDlg::loadDataSet(int index) // 切换数据组时批量刷新控件,避免控件信号被误判为用户修改. bool wasUpdating = m_bUpdatingUi; m_bUpdatingUi = true; - const nmPropertyInterpolationDataSet& dataSet = m_vecDataSets[index]; + nmPropertyInterpolationDataSet& dataSet = m_vecDataSets[index]; m_pNameEdit->setText(dataSet.name); int propertyIndex = m_pPropertyCombo->findData(dataSet.property); m_pPropertyCombo->setCurrentIndex(propertyIndex < 0 ? 0 : propertyIndex); + updateUnitControls(dataSet); + m_pNewValueSpin->setValue(0.0); m_pNuggetSpin->setValue(dataSet.nugget); m_pSillSpin->setValue(dataSet.sill); - m_pRangeSpin->setValue(dataSet.range); + // Range在数据组中保存为m,加载时转换成当前选择的显示单位. + m_pRangeSpin->setValue(convertedUnitValue( + dataSet.range, LENGTH_BASE_UNIT, + m_pRangeUnitCombo->currentText())); int modelIndex = m_pModelCombo->findData(dataSet.model); m_pModelCombo->setCurrentIndex(modelIndex < 0 ? 0 : modelIndex); m_pShowPointsCheck->setChecked(dataSet.showPoints); m_pShowLabelsCheck->setChecked(dataSet.showLabels); + // 重建测点行时保留第0行单位控件,并阻止itemChanged反向修改数据. bool oldTableBlock = m_pPointTable->blockSignals(true); - m_pPointTable->setRowCount(0); + clearPointRows(); 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); + updatePointDisplayValues(); clearTableSelection(); updatePointButtons(); @@ -487,7 +721,13 @@ void nmWxPropertyInterpolationDlg::clearCurrentDataSet() m_pNameEdit->clear(); m_pPropertyCombo->setCurrentIndex(-1); m_pNewValueSpin->setValue(0.0); - m_pPointTable->setRowCount(0); + // 没有当前数据组时保留坐标基准单位,属性值单位置空并禁用. + populateUnitCombo(m_pXUnitCombo, LENGTH_BASE_UNIT, LENGTH_BASE_UNIT); + populateUnitCombo(m_pYUnitCombo, LENGTH_BASE_UNIT, LENGTH_BASE_UNIT); + populateUnitCombo(m_pNewValueUnitCombo, QString(), QString()); + populateUnitCombo(m_pValueUnitCombo, QString(), QString()); + populateUnitCombo(m_pRangeUnitCombo, LENGTH_BASE_UNIT, LENGTH_BASE_UNIT); + clearPointRows(); m_pShowPointsCheck->setChecked(false); m_pShowLabelsCheck->setChecked(false); m_pNuggetSpin->setValue(0.01); @@ -510,15 +750,106 @@ void nmWxPropertyInterpolationDlg::saveCurrentDataSet() nmPropertyInterpolationDataSet& dataSet = m_vecDataSets[m_nCurrentDataSetIndex]; dataSet.name = m_pNameEdit->text(); dataSet.property = m_pPropertyCombo->itemData(m_pPropertyCombo->currentIndex()).toString(); + // 显示单位作为界面偏好保存,Range写回数据组前统一转换为米. + dataSet.xDisplayUnit = m_pXUnitCombo->currentText(); + dataSet.yDisplayUnit = m_pYUnitCombo->currentText(); + dataSet.valueDisplayUnit = propertyBaseUnit(dataSet.property).isEmpty() ? + QString() : m_pValueUnitCombo->currentText(); + dataSet.rangeDisplayUnit = m_pRangeUnitCombo->currentText(); dataSet.nugget = m_pNuggetSpin->value(); dataSet.sill = m_pSillSpin->value(); - dataSet.range = m_pRangeSpin->value(); + dataSet.range = convertedUnitValue( + m_pRangeSpin->value(), dataSet.rangeDisplayUnit, + LENGTH_BASE_UNIT); dataSet.model = m_pModelCombo->itemData(m_pModelCombo->currentIndex()).toInt(); dataSet.showPoints = m_pShowPointsCheck->isChecked(); dataSet.showLabels = m_pShowLabelsCheck->isChecked(); } +void nmWxPropertyInterpolationDlg::updateUnitControls( + nmPropertyInterpolationDataSet& dataSet) +{ + populateUnitCombo(m_pXUnitCombo, LENGTH_BASE_UNIT, + dataSet.xDisplayUnit); + populateUnitCombo(m_pYUnitCombo, LENGTH_BASE_UNIT, + dataSet.yDisplayUnit); + + const QString valueBaseUnit = propertyBaseUnit(dataSet.property); + // 未保存显示单位时按属性默认值初始化,孔隙度使用空单位. + const QString valueDisplayUnit = dataSet.valueDisplayUnit.isEmpty() ? + defaultPropertyDisplayUnit(dataSet.property) : + dataSet.valueDisplayUnit; + populateUnitCombo(m_pNewValueUnitCombo, + valueBaseUnit, valueDisplayUnit); + populateUnitCombo(m_pValueUnitCombo, + valueBaseUnit, valueDisplayUnit); + populateUnitCombo(m_pRangeUnitCombo, LENGTH_BASE_UNIT, + dataSet.rangeDisplayUnit); + dataSet.xDisplayUnit = m_pXUnitCombo->currentText(); + dataSet.yDisplayUnit = m_pYUnitCombo->currentText(); + dataSet.valueDisplayUnit = valueBaseUnit.isEmpty() ? + QString() : m_pValueUnitCombo->currentText(); + dataSet.rangeDisplayUnit = m_pRangeUnitCombo->currentText(); +} + +void nmWxPropertyInterpolationDlg::updatePointDisplayValues() +{ + if(m_nCurrentDataSetIndex < 0 || + m_nCurrentDataSetIndex >= m_vecDataSets.size()) { + return; + } + + const nmPropertyInterpolationDataSet& dataSet = + m_vecDataSets[m_nCurrentDataSetIndex]; + const QString valueBaseUnit = propertyBaseUnit(dataSet.property); + // 测点保留基准值,仅换算表格和地图标签;屏蔽信号避免刷新时反向写回. + bool oldTableBlock = m_pPointTable->blockSignals(true); + for(int pointIndex = 0; pointIndex < dataSet.points.size(); ++pointIndex) { + const int tableRow = pointIndex + FIRST_POINT_ROW; + if(tableRow >= m_pPointTable->rowCount()) { + break; + } + + const nmPropertyInterpolationPointData& point = dataSet.points[pointIndex]; + QTableWidgetItem* xItem = m_pPointTable->item(tableRow, 0); + QTableWidgetItem* yItem = m_pPointTable->item(tableRow, 1); + QTableWidgetItem* valueItem = m_pPointTable->item(tableRow, 2); + if(xItem != NULL) { + xItem->setText(displayValueText(convertedUnitValue( + point.x, LENGTH_BASE_UNIT, + dataSet.xDisplayUnit))); + } + if(yItem != NULL) { + yItem->setText(displayValueText(convertedUnitValue( + point.y, LENGTH_BASE_UNIT, + dataSet.yDisplayUnit))); + } + const double displayValue = convertedUnitValue( + point.value, valueBaseUnit, + dataSet.valueDisplayUnit); + const QString valueText = displayValueText(displayValue); + if(valueItem != NULL) { + valueItem->setText(valueText); + } + + nmObjPoint* marker = markerAt(tableRow); + if(marker != NULL) { + setMarkerLabel(marker, valueText); + marker->update(); + } + } + m_pPointTable->blockSignals(oldTableBlock); +} + +void nmWxPropertyInterpolationDlg::clearPointRows() +{ + // 只删除测点数据行,第0行的单位下拉框始终保留. + if(m_pPointTable != NULL && m_pPointTable->rowCount() > FIRST_POINT_ROW) { + m_pPointTable->setRowCount(FIRST_POINT_ROW); + } +} + void nmWxPropertyInterpolationDlg::syncDataSetsToManager(bool markModified) { if(!m_pDataManager.isNull()) { @@ -536,23 +867,99 @@ void nmWxPropertyInterpolationDlg::updateDataSetButtons() m_nCurrentDataSetIndex < m_vecDataSets.size(); const bool canPickOnMap = hasCurrent && !m_pPlot.isNull() && m_pPlot->m_pPlotView != NULL && m_pPlot->m_pPlot != NULL; + const bool hasValueUnit = hasCurrent && + !propertyBaseUnit(m_vecDataSets[m_nCurrentDataSetIndex].property).isEmpty(); m_pDataSetCombo->setEnabled(hasCurrent); m_pDeleteDataSetButton->setEnabled(hasCurrent); m_pNameEdit->setEnabled(hasCurrent); m_pPropertyCombo->setEnabled(hasCurrent); m_pNewValueSpin->setEnabled(hasCurrent); + m_pNewValueUnitCombo->setEnabled(hasValueUnit); m_pMapPickButton->setEnabled(canPickOnMap); m_pPointTable->setEnabled(hasCurrent); + m_pXUnitCombo->setEnabled(hasCurrent); + m_pYUnitCombo->setEnabled(hasCurrent); + m_pValueUnitCombo->setEnabled(hasValueUnit); m_pShowPointsCheck->setEnabled(hasCurrent); m_pShowLabelsCheck->setEnabled(hasCurrent); m_pNuggetSpin->setEnabled(hasCurrent); m_pSillSpin->setEnabled(hasCurrent); m_pRangeSpin->setEnabled(hasCurrent); + m_pRangeUnitCombo->setEnabled(hasCurrent); m_pModelCombo->setEnabled(hasCurrent); updatePointButtons(); } +void nmWxPropertyInterpolationDlg::updateCalculationDataSetControls() +{ + // 批量重建三个下拉框时阻止选择变化信号写回未完成的界面状态. + bool wasUpdating = m_bUpdatingUi; + m_bUpdatingUi = true; + updateCalculationDataSetControl("k", m_pUseKCheck, + m_pKCalculationDataSetCombo); + updateCalculationDataSetControl("phi", m_pUsePhiCheck, + m_pPhiCalculationDataSetCombo); + updateCalculationDataSetControl("h", m_pUseHCheck, + m_pHCalculationDataSetCombo); + m_bUpdatingUi = wasUpdating; +} + +void nmWxPropertyInterpolationDlg::updateCalculationDataSetControl( + const QString& property, + QCheckBox* checkBox, + QComboBox* comboBox) +{ + if(checkBox == NULL || comboBox == NULL) { + return; + } + + // 下拉项保存原数据组下标,并根据useForCalculation恢复当前选择. + comboBox->clear(); + int selectedComboIndex = -1; + for(int dataSetIndex = 0; dataSetIndex < m_vecDataSets.size(); ++dataSetIndex) { + const nmPropertyInterpolationDataSet& dataSet = m_vecDataSets[dataSetIndex]; + if(dataSet.property != property) { + continue; + } + + comboBox->addItem(dataSet.name, dataSetIndex); + if(selectedComboIndex < 0 && dataSet.useForCalculation) { + selectedComboIndex = comboBox->count() - 1; + } + } + + comboBox->setCurrentIndex(selectedComboIndex >= 0 ? selectedComboIndex : + (comboBox->count() > 0 ? 0 : -1)); + checkBox->setChecked(selectedComboIndex >= 0); + checkBox->setEnabled(comboBox->count() > 0); + comboBox->setEnabled(checkBox->isChecked() && comboBox->count() > 0); +} + +void nmWxPropertyInterpolationDlg::saveCalculationSelection( + const QString& property, + QCheckBox* checkBox, + QComboBox* comboBox) +{ + // 先清除同属性的旧标记,保证每个属性最多启用一个插值数据组. + for(int dataSetIndex = 0; dataSetIndex < m_vecDataSets.size(); ++dataSetIndex) { + if(m_vecDataSets[dataSetIndex].property == property) { + m_vecDataSets[dataSetIndex].useForCalculation = false; + } + } + + if(checkBox == NULL || comboBox == NULL || !checkBox->isChecked()) { + return; + } + + const int selectedDataSetIndex = comboBox->itemData( + comboBox->currentIndex()).toInt(); + if(selectedDataSetIndex >= 0 && selectedDataSetIndex < m_vecDataSets.size() && + m_vecDataSets[selectedDataSetIndex].property == property) { + m_vecDataSets[selectedDataSetIndex].useForCalculation = true; + } +} + void nmWxPropertyInterpolationDlg::onDataSetChanged(int index) { if(m_bUpdatingUi || index < 0 || index >= m_vecDataSets.size() || @@ -582,6 +989,7 @@ void nmWxPropertyInterpolationDlg::onAddDataSet() m_nCurrentDataSetIndex = newIndex; loadDataSet(newIndex); updateDataSetButtons(); + updateCalculationDataSetControls(); syncDataSetsToManager(true); schedulePreviewRefresh(); } @@ -608,6 +1016,7 @@ void nmWxPropertyInterpolationDlg::onDeleteDataSet() m_nCurrentDataSetIndex = newIndex; loadDataSet(newIndex); updateDataSetButtons(); + updateCalculationDataSetControls(); syncDataSetsToManager(true); schedulePreviewRefresh(); } @@ -621,6 +1030,30 @@ void nmWxPropertyInterpolationDlg::onDataSetNameChanged(const QString& name) m_vecDataSets[m_nCurrentDataSetIndex].name = name; m_pDataSetCombo->setItemText(m_nCurrentDataSetIndex, name); + updateCalculationDataSetControls(); + syncDataSetsToManager(true); + schedulePreviewRefresh(); +} + +void nmWxPropertyInterpolationDlg::onCurrentDataSetPropertyChanged() +{ + if(m_bUpdatingUi || m_nCurrentDataSetIndex < 0 || + m_nCurrentDataSetIndex >= m_vecDataSets.size()) { + return; + } + + // 数据组切换属性后取消原有求解选择,并切换到对应的基准显示单位. + nmPropertyInterpolationDataSet& dataSet = + m_vecDataSets[m_nCurrentDataSetIndex]; + dataSet.useForCalculation = false; + dataSet.property = m_pPropertyCombo->itemData( + m_pPropertyCombo->currentIndex()).toString(); + dataSet.valueDisplayUnit = defaultPropertyDisplayUnit(dataSet.property); + updateUnitControls(dataSet); + m_pNewValueSpin->setValue(0.0); + updatePointDisplayValues(); + saveCurrentDataSet(); + updateCalculationDataSetControls(); syncDataSetsToManager(true); schedulePreviewRefresh(); } @@ -636,6 +1069,114 @@ void nmWxPropertyInterpolationDlg::onCurrentDataSetEdited() schedulePreviewRefresh(); } +void nmWxPropertyInterpolationDlg::onXDisplayUnitChanged(const QString& unit) +{ + if(m_bUpdatingUi || m_nCurrentDataSetIndex < 0 || + m_nCurrentDataSetIndex >= m_vecDataSets.size()) { + return; + } + + // 坐标基准值保持为m,仅刷新X列的显示文本. + m_vecDataSets[m_nCurrentDataSetIndex].xDisplayUnit = unit; + updatePointDisplayValues(); + syncDataSetsToManager(true); +} + +void nmWxPropertyInterpolationDlg::onYDisplayUnitChanged(const QString& unit) +{ + if(m_bUpdatingUi || m_nCurrentDataSetIndex < 0 || + m_nCurrentDataSetIndex >= m_vecDataSets.size()) { + return; + } + + // 坐标基准值保持为m,仅刷新Y列的显示文本. + m_vecDataSets[m_nCurrentDataSetIndex].yDisplayUnit = unit; + updatePointDisplayValues(); + syncDataSetsToManager(true); +} + +void nmWxPropertyInterpolationDlg::onValueDisplayUnitChanged(const QString& unit) +{ + if(m_bUpdatingUi || m_nCurrentDataSetIndex < 0 || + m_nCurrentDataSetIndex >= m_vecDataSets.size()) { + return; + } + + nmPropertyInterpolationDataSet& dataSet = + m_vecDataSets[m_nCurrentDataSetIndex]; + const QString baseUnit = propertyBaseUnit(dataSet.property); + if(baseUnit.isEmpty() || unit.isEmpty() || + unit == dataSet.valueDisplayUnit) { + return; + } + + // 经基准单位中转,切换单位时不会改变待添加值表示的物理量. + const double baseNewValue = convertedUnitValue( + m_pNewValueSpin->value(), + dataSet.valueDisplayUnit, baseUnit); + dataSet.valueDisplayUnit = unit; + + // 新值和表头共用显示单位,联动时屏蔽信号以避免递归触发. + bool oldBlock = m_pNewValueUnitCombo->blockSignals(true); + m_pNewValueUnitCombo->setCurrentIndex( + m_pNewValueUnitCombo->findText(unit)); + m_pNewValueUnitCombo->blockSignals(oldBlock); + oldBlock = m_pValueUnitCombo->blockSignals(true); + m_pValueUnitCombo->setCurrentIndex(m_pValueUnitCombo->findText(unit)); + m_pValueUnitCombo->blockSignals(oldBlock); + oldBlock = m_pNewValueSpin->blockSignals(true); + m_pNewValueSpin->setValue(convertedUnitValue( + baseNewValue, baseUnit, unit)); + m_pNewValueSpin->blockSignals(oldBlock); + + updatePointDisplayValues(); + syncDataSetsToManager(true); + schedulePreviewRefresh(); +} + +void nmWxPropertyInterpolationDlg::onRangeDisplayUnitChanged(const QString& unit) +{ + if(m_bUpdatingUi || unit.isEmpty() || m_nCurrentDataSetIndex < 0 || + m_nCurrentDataSetIndex >= m_vecDataSets.size()) { + return; + } + + nmPropertyInterpolationDataSet& dataSet = + m_vecDataSets[m_nCurrentDataSetIndex]; + // 先按旧显示单位还原米制基准值,再使用新单位回显. + dataSet.range = convertedUnitValue( + m_pRangeSpin->value(), dataSet.rangeDisplayUnit, + LENGTH_BASE_UNIT); + dataSet.rangeDisplayUnit = unit; + + bool oldBlock = m_pRangeSpin->blockSignals(true); + m_pRangeSpin->setValue(convertedUnitValue( + dataSet.range, LENGTH_BASE_UNIT, unit)); + m_pRangeSpin->blockSignals(oldBlock); + syncDataSetsToManager(true); +} + +void nmWxPropertyInterpolationDlg::onCalculationSelectionChanged() +{ + if(m_bUpdatingUi) { + return; + } + + // 先保存当前编辑内容,再统一更新三个属性的唯一求解数据组. + saveCurrentDataSet(); + saveCalculationSelection("k", m_pUseKCheck, + m_pKCalculationDataSetCombo); + saveCalculationSelection("phi", m_pUsePhiCheck, + m_pPhiCalculationDataSetCombo); + saveCalculationSelection("h", m_pUseHCheck, + m_pHCalculationDataSetCombo); + + m_pKCalculationDataSetCombo->setEnabled(m_pUseKCheck->isChecked()); + m_pPhiCalculationDataSetCombo->setEnabled(m_pUsePhiCheck->isChecked()); + m_pHCalculationDataSetCombo->setEnabled(m_pUseHCheck->isChecked()); + syncDataSetsToManager(true); +} + bool nmWxPropertyInterpolationDlg::eventFilter(QObject* watched, QEvent* event) { // 点击表格空白处或其他控件时取消测点行的选中状态. @@ -706,10 +1247,15 @@ void nmWxPropertyInterpolationDlg::appendPoint(const QPointF& valuePoint) } nmPropertyInterpolationDataSet& dataSet = m_vecDataSets[m_nCurrentDataSetIndex]; - double pointValue = m_pNewValueSpin->value(); + const QString valueBaseUnit = propertyBaseUnit(dataSet.property); + const double displayPointValue = m_pNewValueSpin->value(); + // 属性值按求解器基准单位保存,地图标签继续使用当前显示值. + const double pointValue = convertedUnitValue( + displayPointValue, dataSet.valueDisplayUnit, + valueBaseUnit); nmPropertyInterpolationPointData point(valuePoint.x(), valuePoint.y(), pointValue); - QString markerName = createMarker(valuePoint, pointValue, - dataSet.showPoints, dataSet.showLabels); + QString markerName = createMarker(valuePoint, displayPointValue, + dataSet.showPoints, dataSet.showLabels); // 测点数据、地图标记和表格行按相同顺序同步追加. dataSet.points.append(point); @@ -728,20 +1274,38 @@ void nmWxPropertyInterpolationDlg::appendPointRow( const nmPropertyInterpolationPointData& point, const QString& markerName) { + // rowCount已包含单位行,新插入行天然与points下标保持FIRST_POINT_ROW偏移. int row = m_pPointTable->rowCount(); m_pPointTable->insertRow(row); - QTableWidgetItem* xItem = new QTableWidgetItem(QString::number(point.x, 'g', 15)); + QString xUnit = LENGTH_BASE_UNIT; + QString yUnit = LENGTH_BASE_UNIT; + QString valueUnit; + QString valueBaseUnit; + if(m_nCurrentDataSetIndex >= 0 && + m_nCurrentDataSetIndex < m_vecDataSets.size()) { + const nmPropertyInterpolationDataSet& dataSet = + m_vecDataSets[m_nCurrentDataSetIndex]; + xUnit = dataSet.xDisplayUnit; + yUnit = dataSet.yDisplayUnit; + valueUnit = dataSet.valueDisplayUnit; + valueBaseUnit = propertyBaseUnit(dataSet.property); + } + + QTableWidgetItem* xItem = new QTableWidgetItem(displayValueText( + convertedUnitValue(point.x, LENGTH_BASE_UNIT, xUnit))); xItem->setFlags(xItem->flags() & ~Qt::ItemIsEditable); + // 将地图标记名称绑定在X列,后续可由表格行直接定位对应标记. xItem->setData(Qt::UserRole, markerName); m_pPointTable->setItem(row, 0, xItem); - QTableWidgetItem* yItem = new QTableWidgetItem(QString::number(point.y, 'g', 15)); + QTableWidgetItem* yItem = new QTableWidgetItem(displayValueText( + convertedUnitValue(point.y, LENGTH_BASE_UNIT, yUnit))); 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))); + m_pPointTable->setItem(row, 2, new QTableWidgetItem(displayValueText( + convertedUnitValue(point.value, valueBaseUnit, valueUnit)))); } QString nmWxPropertyInterpolationDlg::createMarker(const QPointF& valuePosition, @@ -793,6 +1357,7 @@ void nmWxPropertyInterpolationDlg::createMarkersForAllDataSets() return; } + // 地图标签使用显示单位,数据组中的测点基准值保持不变. for(int dataSetIndex = 0; dataSetIndex < m_vecDataSets.size(); ++dataSetIndex) { const nmPropertyInterpolationDataSet& dataSet = m_vecDataSets[dataSetIndex]; QStringList markerNames; @@ -800,8 +1365,11 @@ void nmWxPropertyInterpolationDlg::createMarkersForAllDataSets() 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)); + const double displayValue = convertedUnitValue( + point.value, propertyBaseUnit(dataSet.property), + dataSet.valueDisplayUnit); + markerNames.append(createMarker(valuePosition, displayValue, + dataSet.showPoints, dataSet.showLabels)); } m_vecMarkerNames[dataSetIndex] = markerNames; @@ -831,7 +1399,8 @@ void nmWxPropertyInterpolationDlg::removeAllMarkers() QString nmWxPropertyInterpolationDlg::markerNameAt(int row) const { - if(m_pPointTable == NULL || row < 0 || row >= m_pPointTable->rowCount()) { + if(m_pPointTable == NULL || row < FIRST_POINT_ROW || + row >= m_pPointTable->rowCount()) { return QString(); } @@ -867,20 +1436,33 @@ void nmWxPropertyInterpolationDlg::removeMarkerByName(const QString& markerName) void nmWxPropertyInterpolationDlg::onPointSelectionChanged() { + // 单位行只用于切换显示单位,不作为可删除的测点行. + if(m_pPointTable->currentRow() == POINT_UNIT_ROW) { + clearTableSelection(); + return; + } updatePointButtons(); } void nmWxPropertyInterpolationDlg::onPointItemChanged(QTableWidgetItem* item) { + // 表格行减去单位行偏移后,才是数据组中的测点下标. + const int pointIndex = item == NULL ? -1 : + item->row() - FIRST_POINT_ROW; if(m_bUpdatingUi || item == NULL || item->column() != 2 || + pointIndex < 0 || m_nCurrentDataSetIndex < 0 || m_nCurrentDataSetIndex >= m_vecDataSets.size() || - item->row() >= m_vecDataSets[m_nCurrentDataSetIndex].points.size()) { + pointIndex >= m_vecDataSets[m_nCurrentDataSetIndex].points.size()) { return; } // 数值修改后同步更新数据组和地图标签,坐标列保持只读. - m_vecDataSets[m_nCurrentDataSetIndex].points[item->row()].value = item->text().toDouble(); + nmPropertyInterpolationDataSet& dataSet = + m_vecDataSets[m_nCurrentDataSetIndex]; + dataSet.points[pointIndex].value = convertedUnitValue( + item->text().toDouble(), dataSet.valueDisplayUnit, + propertyBaseUnit(dataSet.property)); nmObjPoint* marker = markerAt(item->row()); if(marker != NULL) { setMarkerLabel(marker, item->text()); @@ -893,17 +1475,19 @@ void nmWxPropertyInterpolationDlg::onPointItemChanged(QTableWidgetItem* item) void nmWxPropertyInterpolationDlg::onDeleteSelectedPoint() { int row = m_pPointTable->currentRow(); - if(row < 0 || m_nCurrentDataSetIndex < 0 || + // 同时删除相同下标的数据、地图标记和表格行,保持三者一一对应. + const int pointIndex = row - FIRST_POINT_ROW; + if(pointIndex < 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(pointIndex < m_vecDataSets[m_nCurrentDataSetIndex].points.size()) { + m_vecDataSets[m_nCurrentDataSetIndex].points.remove(pointIndex); } - if(row < m_vecMarkerNames[m_nCurrentDataSetIndex].size()) { - m_vecMarkerNames[m_nCurrentDataSetIndex].removeAt(row); + if(pointIndex < m_vecMarkerNames[m_nCurrentDataSetIndex].size()) { + m_vecMarkerNames[m_nCurrentDataSetIndex].removeAt(pointIndex); } m_pPointTable->removeRow(row); clearTableSelection(); @@ -921,7 +1505,7 @@ void nmWxPropertyInterpolationDlg::onClearPoints() removeDataSetMarkers(m_nCurrentDataSetIndex); m_vecDataSets[m_nCurrentDataSetIndex].points.clear(); - m_pPointTable->setRowCount(0); + clearPointRows(); clearTableSelection(); updatePointButtons(); syncDataSetsToManager(true); @@ -964,8 +1548,11 @@ 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); + m_pDeletePointButton->setEnabled( + hasCurrent && m_pPointTable->currentRow() >= FIRST_POINT_ROW); + m_pClearPointsButton->setEnabled( + hasCurrent && m_pPointTable->rowCount() > FIRST_POINT_ROW); + // Kriging预览至少需要两个已知测点. m_pPreviewButton->setEnabled(hasCurrent && m_vecDataSets[m_nCurrentDataSetIndex].points.size() >= 2); } @@ -1095,17 +1682,40 @@ void nmWxPropertyInterpolationDlg::updatePreviewWindow(bool activateWindow) return; } + // Kriging使用内部基准值;渲染前统一转换表面和测点的显示单位. + const QString valueBaseUnit = propertyBaseUnit(dataSet.property); + QVector displayInterpolationValues; + displayInterpolationValues.reserve(interpolationValues.size()); + for(int i = 0; i < interpolationValues.size(); ++i) { + displayInterpolationValues.append(convertedUnitValue( + interpolationValues[i], + valueBaseUnit, + dataSet.valueDisplayUnit)); + } + QVector displayMeasurementValues; + displayMeasurementValues.reserve(measurementValues.size()); + for(int i = 0; i < measurementValues.size(); ++i) { + displayMeasurementValues.append(convertedUnitValue( + measurementValues[i], + valueBaseUnit, + dataSet.valueDisplayUnit)); + } + QString scalarTitle = m_pPropertyCombo->currentText(); + if(!dataSet.valueDisplayUnit.isEmpty()) { + scalarTitle += QString(" (%1)").arg(dataSet.valueDisplayUnit); + } + // 预览窗口只负责裁剪和渲染,不修改数据组及正式求解参数. if(m_pPreviewDialog.isNull()) { m_pPreviewDialog = new nmWxPropertyInterpolationPreviewDlg( dataSet.name, - m_pPropertyCombo->currentText(), + scalarTitle, previewBounds, columnCount, rowCount, - interpolationValues, + displayInterpolationValues, measurementPoints, - measurementValues, + displayMeasurementValues, outlinePoints, dataSet.showPoints, dataSet.showLabels, @@ -1115,13 +1725,13 @@ void nmWxPropertyInterpolationDlg::updatePreviewWindow(bool activateWindow) else { m_pPreviewDialog->updatePreview( dataSet.name, - m_pPropertyCombo->currentText(), + scalarTitle, previewBounds, columnCount, rowCount, - interpolationValues, + displayInterpolationValues, measurementPoints, - measurementValues, + displayMeasurementValues, outlinePoints, dataSet.showPoints, dataSet.showLabels);