You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nmWTAI-Platform/Src/nmNum/nmSubWxs/nmWxPropertyInterpolationDl...

1936 lines
72 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "nmWxPropertyInterpolationDlg.h"
#include <QAbstractItemView>
#include <QApplication>
#include <QCheckBox>
#include <QComboBox>
#include <QCoreApplication>
#include <QDoubleSpinBox>
#include <QEvent>
#include <QFormLayout>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QIcon>
#include <QGridLayout>
#include <QLabel>
#include <QLineEdit>
#include <QMessageBox>
#include <QMouseEvent>
#include <QPainter>
#include <QPolygonF>
#include <QPushButton>
#include <QSize>
#include <QTableWidget>
#include <QTableWidgetItem>
#include <QTimer>
#include <QTransform>
#include <QVBoxLayout>
#include <QWidget>
#include <QtCore/qmath.h>
#include "nmCalculationUtils.h"
#include "nmDataOutline.h"
#include "nmGuiPlot.h"
#include "nmObjPoint.h"
#include "nmObjPointWell.h"
#include "nmWxPropertyInterpolationPreviewDlg.h"
#include "iUnitGroup.h"
#include "iUnitHelper.h"
#include "tCurvePlotView.h"
#include "ZxDataWell.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)
{
return QCoreApplication::translate("nmWxPropertyInterpolationDlg", sourceText);
}
// 创建统一格式的非负数值输入框.
QDoubleSpinBox* createNumberSpinBox(QWidget* parent, double value)
{
QDoubleSpinBox* spinBox = new QDoubleSpinBox(parent);
spinBox->setRange(0.0, 1.0e12);
spinBox->setDecimals(6);
spinBox->setValue(value);
spinBox->setButtonSymbols(QAbstractSpinBox::NoButtons);
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
{
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<ZxObjText*>(marker->at(0));
if(label != NULL) {
label->setText(text);
label->setTextColor(QColor(30, 30, 30));
}
}
// 将储层边界转换成预览裁剪使用的多边形,并计算规则采样范围.
bool createPreviewOutline(nmDataOutline* outline,
QVector<QPointF>& outlinePoints,
QRectF& bounds)
{
outlinePoints.clear();
bounds = QRectF();
if(outline == NULL) {
return false;
}
if(outline->getOutlineType() == NM_Round_Outline_Type) {
// 圆形边界离散成多边形,便于预览窗口统一裁剪.
const QPointF center = outline->getCenter();
const double radius = outline->getRadius();
if(radius <= 0.0) {
return false;
}
const int segmentCount = 72;
const double fullCircle = 6.28318530717958647692;
for(int i = 0; i < segmentCount; ++i) {
const double angle = fullCircle * i / segmentCount;
outlinePoints.append(QPointF(center.x() + radius * qCos(angle),
center.y() + radius * qSin(angle)));
}
} else {
outlinePoints = outline->getOutlinePoints();
if(outlinePoints.size() > 3 &&
outlinePoints.first() == outlinePoints.last()) {
outlinePoints.remove(outlinePoints.size() - 1);
}
}
if(outlinePoints.size() < 3) {
return false;
}
bounds = QPolygonF(outlinePoints).boundingRect().normalized();
return bounds.width() > 0.0 && bounds.height() > 0.0;
}
}
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),
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),
m_pShowLabelsCheck(NULL),
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_pPreviewDialog(NULL),
m_pPreviewRefreshTimer(NULL)
{
setWindowTitle(interpolationText("Property Interpolation"));
setWindowModality(Qt::NonModal);
setModal(false);
setMinimumSize(600, 620);
resize(640, 680);
// 合并连续编辑触发的刷新,避免每次数值变化都立即重新插值.
m_pPreviewRefreshTimer = new QTimer(this);
m_pPreviewRefreshTimer->setSingleShot(true);
m_pPreviewRefreshTimer->setInterval(200);
connect(m_pPreviewRefreshTimer, SIGNAL(timeout()),
this, SLOT(refreshPreview()));
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()
{
const int topControlWidth = 350;
const int compactComboWidth = 200;
QVBoxLayout* mainLayout = new QVBoxLayout(this);
mainLayout->setContentsMargins(12, 10, 12, 10);
mainLayout->setSpacing(8);
// 数据组、名称和属性共用一个表单,保证三行标签及输入控件对齐.
QFormLayout* dataSetLayout = new QFormLayout;
dataSetLayout->setContentsMargins(0, 0, 0, 0);
dataSetLayout->setHorizontalSpacing(8);
dataSetLayout->setVerticalSpacing(6);
dataSetLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
QWidget* dataSetSelectWidget = new QWidget(this);
dataSetSelectWidget->setMaximumWidth(topControlWidth);
QHBoxLayout* dataSetSelectLayout = new QHBoxLayout(dataSetSelectWidget);
dataSetSelectLayout->setContentsMargins(0, 0, 0, 0);
dataSetSelectLayout->setSpacing(6);
m_pDataSetCombo = new QComboBox(dataSetSelectWidget);
dataSetSelectLayout->addWidget(m_pDataSetCombo, 1);
QString iconDir = QCoreApplication::applicationDirPath();
iconDir = iconDir.section('/', 0, -2) + "/Res/Icon/";
m_pAddDataSetButton = new QPushButton(dataSetSelectWidget);
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(dataSetSelectWidget);
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);
dataSetLayout->addRow(interpolationText("Dataset:"), dataSetSelectWidget);
m_pNameEdit = new QLineEdit(this);
m_pNameEdit->setMaximumWidth(topControlWidth);
dataSetLayout->addRow(interpolationText("Name:"), m_pNameEdit);
m_pPropertyCombo = new QComboBox(this);
m_pPropertyCombo->setMaximumWidth(topControlWidth);
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);
mainLayout->addLayout(dataSetLayout);
// 测点数据录入区域.
QGroupBox* pointGroup = new QGroupBox(interpolationText("Measurement Points"), this);
QVBoxLayout* pointLayout = new QVBoxLayout(pointGroup);
pointLayout->setContentsMargins(10, 8, 10, 10);
pointLayout->setSpacing(6);
QHBoxLayout* newPointLayout = new QHBoxLayout;
newPointLayout->setSpacing(6);
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->setFixedWidth(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->setIcon(QIcon(iconDir + "AddPoint.png"));
m_pMapPickButton->setIconSize(QSize(16, 16));
m_pMapPickButton->setMinimumWidth(100);
m_pMapPickButton->setCheckable(true);
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(1, 3, pointGroup);
QStringList headers;
headers << interpolationText("X") << interpolationText("Y") << interpolationText("Value");
m_pPointTable->setHorizontalHeaderLabels(headers);
m_pPointTable->verticalHeader()->setVisible(true);
m_pPointTable->verticalHeader()->setFixedWidth(36);
m_pPointTable->verticalHeader()->setDefaultAlignment(Qt::AlignCenter);
// 第0行为单位选择不占用测点序号.
m_pPointTable->setVerticalHeaderItem(
POINT_UNIT_ROW, new QTableWidgetItem(QString()));
m_pPointTable->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
m_pPointTable->setSelectionBehavior(QAbstractItemView::SelectRows);
m_pPointTable->setSelectionMode(QAbstractItemView::SingleSelection);
m_pPointTable->setAlternatingRowColors(true);
m_pPointTable->setMinimumHeight(170);
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;
pointButtonLayout->setSpacing(8);
m_pShowPointsCheck = new QCheckBox(interpolationText("Show measurement points"), pointGroup);
m_pShowPointsCheck->setChecked(true);
pointButtonLayout->addWidget(m_pShowPointsCheck);
m_pShowLabelsCheck = new QCheckBox(interpolationText("Show labels"), pointGroup);
m_pShowLabelsCheck->setChecked(true);
pointButtonLayout->addWidget(m_pShowLabelsCheck);
pointButtonLayout->addStretch();
m_pDeletePointButton = new QPushButton(interpolationText("Delete Selected"), pointGroup);
m_pDeletePointButton->setMinimumWidth(84);
m_pDeletePointButton->setEnabled(false);
pointButtonLayout->addWidget(m_pDeletePointButton);
m_pClearPointsButton = new QPushButton(interpolationText("Clear"), pointGroup);
m_pClearPointsButton->setMinimumWidth(72);
m_pClearPointsButton->setEnabled(false);
pointButtonLayout->addWidget(m_pClearPointsButton);
pointLayout->addLayout(pointButtonLayout);
mainLayout->addWidget(pointGroup, 1);
// Kriging参数采用两行双列布局保持信息完整并压缩纵向空间.
QGroupBox* parameterGroup = new QGroupBox(interpolationText("Kriging Parameters"), this);
QGridLayout* parameterLayout = new QGridLayout(parameterGroup);
parameterLayout->setContentsMargins(10, 8, 10, 10);
parameterLayout->setHorizontalSpacing(8);
parameterLayout->setVerticalSpacing(6);
m_pNuggetSpin = createNumberSpinBox(parameterGroup, 0.01);
parameterLayout->addWidget(new QLabel(interpolationText("Nugget:"), parameterGroup), 0, 0);
parameterLayout->addWidget(m_pNuggetSpin, 0, 1);
m_pSillSpin = createNumberSpinBox(parameterGroup, 100.0);
parameterLayout->addWidget(new QLabel(interpolationText("Sill:"), parameterGroup), 0, 2);
parameterLayout->addWidget(m_pSillSpin, 0, 3);
QWidget* rangeWidget = new QWidget(parameterGroup);
QHBoxLayout* rangeLayout = new QHBoxLayout(rangeWidget);
rangeLayout->setContentsMargins(0, 0, 0, 0);
rangeLayout->setSpacing(6);
m_pRangeSpin = createNumberSpinBox(rangeWidget, 1000.0);
rangeLayout->addWidget(m_pRangeSpin, 1);
m_pRangeUnitCombo = new QComboBox(rangeWidget);
m_pRangeUnitCombo->setFixedWidth(72);
populateUnitCombo(m_pRangeUnitCombo, LENGTH_BASE_UNIT, LENGTH_BASE_UNIT);
rangeLayout->addWidget(m_pRangeUnitCombo);
parameterLayout->addWidget(new QLabel(interpolationText("Range:"), parameterGroup), 1, 0);
parameterLayout->addWidget(rangeWidget, 1, 1);
m_pModelCombo = new QComboBox(parameterGroup);
m_pModelCombo->setFixedWidth(compactComboWidth);
m_pModelCombo->addItem(interpolationText("Spherical (0)"), 0);
m_pModelCombo->addItem(interpolationText("Exponential (1)"), 1);
m_pModelCombo->addItem(interpolationText("Gaussian (2)"), 2);
parameterLayout->addWidget(new QLabel(interpolationText("Model:"), parameterGroup), 1, 2);
parameterLayout->addWidget(m_pModelCombo, 1, 3);
parameterLayout->setColumnStretch(1, 1);
parameterLayout->setColumnStretch(3, 1);
mainLayout->addWidget(parameterGroup);
// 分别指定正式求解时需要使用插值结果的属性和数据组.
QGroupBox* calculationGroup = new QGroupBox(
interpolationText("Use Interpolation in Solver"), this);
QGridLayout* calculationLayout = new QGridLayout(calculationGroup);
calculationLayout->setContentsMargins(10, 8, 10, 10);
calculationLayout->setHorizontalSpacing(8);
calculationLayout->setVerticalSpacing(6);
m_pUseKCheck = new QCheckBox(interpolationText("Permeability k"), calculationGroup);
m_pKCalculationDataSetCombo = new QComboBox(calculationGroup);
m_pKCalculationDataSetCombo->setFixedWidth(compactComboWidth);
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);
m_pPhiCalculationDataSetCombo->setFixedWidth(compactComboWidth);
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);
m_pHCalculationDataSetCombo->setFixedWidth(compactComboWidth);
calculationLayout->addWidget(m_pUseHCheck, 2, 0);
calculationLayout->addWidget(m_pHCalculationDataSetCombo, 2, 1);
calculationLayout->setColumnMinimumWidth(1, compactComboWidth);
calculationLayout->setColumnStretch(2, 1);
mainLayout->addWidget(calculationGroup);
// 底部操作按钮.
QHBoxLayout* buttonLayout = new QHBoxLayout;
m_pPreviewButton = new QPushButton(interpolationText("Preview"), this);
m_pPreviewButton->setMinimumWidth(84);
m_pPreviewButton->setEnabled(false);
buttonLayout->addWidget(m_pPreviewButton);
buttonLayout->addStretch();
QPushButton* closeButton = new QPushButton(interpolationText("Close"), this);
closeButton->setMinimumWidth(84);
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(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)));
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(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()));
}
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();
updateCalculationDataSetControls();
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;
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);
// 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);
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();
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);
// 没有当前数据组时保留坐标基准单位,属性值单位置空并禁用.
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);
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();
// 显示单位作为界面偏好保存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 = 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);
}
updatePointRowNumbers();
}
void nmWxPropertyInterpolationDlg::updatePointRowNumbers()
{
if(m_pPointTable == NULL) {
return;
}
// 单位行留空测点数据行始终从1开始连续编号.
for(int row = POINT_UNIT_ROW; row < m_pPointTable->rowCount(); ++row) {
const QString number = row < FIRST_POINT_ROW ?
QString() : QString::number(row - FIRST_POINT_ROW + 1);
QTableWidgetItem* headerItem = m_pPointTable->verticalHeaderItem(row);
if(headerItem == NULL) {
m_pPointTable->setVerticalHeaderItem(row,
new QTableWidgetItem(number));
}
else {
headerItem->setText(number);
}
}
}
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;
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() ||
index == m_nCurrentDataSetIndex) {
return;
}
saveCurrentDataSet();
syncDataSetsToManager(false);
m_nCurrentDataSetIndex = index;
loadDataSet(index);
schedulePreviewRefresh();
}
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();
updateCalculationDataSetControls();
syncDataSetsToManager(true);
schedulePreviewRefresh();
}
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();
updateCalculationDataSetControls();
syncDataSetsToManager(true);
schedulePreviewRefresh();
}
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);
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();
}
void nmWxPropertyInterpolationDlg::onCurrentDataSetEdited()
{
if(m_bUpdatingUi) {
return;
}
saveCurrentDataSet();
syncDataSetsToManager(true);
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)
{
// 点击表格空白处或其他控件时取消测点行的选中状态.
if(event != NULL && event->type() == QEvent::MouseButtonPress && m_pPointTable != NULL) {
QWidget* clickedWidget = qobject_cast<QWidget*>(watched);
if(clickedWidget != NULL) {
bool isTableViewport = clickedWidget == m_pPointTable->viewport() ||
m_pPointTable->viewport()->isAncestorOf(clickedWidget);
if(clickedWidget == m_pPointTable->viewport()) {
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(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];
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, displayPointValue,
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);
schedulePreviewRefresh();
}
void nmWxPropertyInterpolationDlg::appendPointRow(
const nmPropertyInterpolationPointData& point,
const QString& markerName)
{
// rowCount已包含单位行新插入行天然与points下标保持FIRST_POINT_ROW偏移.
int row = m_pPointTable->rowCount();
m_pPointTable->insertRow(row);
m_pPointTable->setVerticalHeaderItem(
row, new QTableWidgetItem(QString::number(
row - FIRST_POINT_ROW + 1)));
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)));
// 将地图标记名称绑定在X列后续可由表格行直接定位对应标记.
xItem->setData(Qt::UserRole, markerName);
m_pPointTable->setItem(row, 0, xItem);
QTableWidgetItem* yItem = new QTableWidgetItem(displayValueText(
convertedUnitValue(point.y, LENGTH_BASE_UNIT, yUnit)));
m_pPointTable->setItem(row, 1, yItem);
m_pPointTable->setItem(row, 2, new QTableWidgetItem(displayValueText(
convertedUnitValue(point.value, valueBaseUnit, valueUnit))));
}
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<QPointF> 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);
const double displayValue = convertedUnitValue(
point.value, propertyBaseUnit(dataSet.property),
dataSet.valueDisplayUnit);
markerNames.append(createMarker(valuePosition, displayValue,
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 < FIRST_POINT_ROW ||
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<nmObjPoint*>(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()
{
// 单位行只用于切换显示单位,不作为可删除的测点行.
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() < 0 ||
item->column() > 2 ||
pointIndex < 0 ||
m_nCurrentDataSetIndex < 0 ||
m_nCurrentDataSetIndex >= m_vecDataSets.size() ||
pointIndex >= m_vecDataSets[m_nCurrentDataSetIndex].points.size()) {
return;
}
nmPropertyInterpolationDataSet& dataSet =
m_vecDataSets[m_nCurrentDataSetIndex];
nmPropertyInterpolationPointData& point = dataSet.points[pointIndex];
// X、Y及属性值分别按当前显示单位换算回数据中心使用的基准单位.
QString baseUnit;
QString displayUnit;
double oldBaseValue = 0.0;
if(item->column() == 0) {
baseUnit = LENGTH_BASE_UNIT;
displayUnit = dataSet.xDisplayUnit;
oldBaseValue = point.x;
}
else if(item->column() == 1) {
baseUnit = LENGTH_BASE_UNIT;
displayUnit = dataSet.yDisplayUnit;
oldBaseValue = point.y;
}
else {
baseUnit = propertyBaseUnit(dataSet.property);
displayUnit = dataSet.valueDisplayUnit;
oldBaseValue = point.value;
}
bool valueOk = false;
const double displayValue = item->text().toDouble(&valueOk);
if(!valueOk || (item->column() == 2 && displayValue < 0.0)) {
// 坐标允许为负数;属性值仍要求非负,非法输入恢复为修改前的值.
const double oldDisplayValue = convertedUnitValue(
oldBaseValue, baseUnit, displayUnit);
const bool oldBlock = m_pPointTable->blockSignals(true);
item->setText(displayValueText(oldDisplayValue));
m_pPointTable->blockSignals(oldBlock);
return;
}
const double baseValue = convertedUnitValue(
displayValue, displayUnit, baseUnit);
if(item->column() == 0) {
point.x = baseValue;
}
else if(item->column() == 1) {
point.y = baseValue;
}
else {
point.value = baseValue;
}
const QString displayText = displayValueText(displayValue);
if(item->text() != displayText) {
const bool oldBlock = m_pPointTable->blockSignals(true);
item->setText(displayText);
m_pPointTable->blockSignals(oldBlock);
}
// 坐标修改后移动Map标记属性值修改后刷新标记标签.
nmObjPoint* marker = markerAt(item->row());
if(marker != NULL) {
if(item->column() < 2) {
QVector<QPointF> positions;
positions.append(QPointF(point.x, point.y));
marker->setAllValues(positions);
}
else {
setMarkerLabel(marker, displayText);
}
marker->update();
}
syncDataSetsToManager(true);
schedulePreviewRefresh();
}
void nmWxPropertyInterpolationDlg::onDeleteSelectedPoint()
{
int row = m_pPointTable->currentRow();
// 同时删除相同下标的数据、地图标记和表格行,保持三者一一对应.
const int pointIndex = row - FIRST_POINT_ROW;
if(pointIndex < 0 || m_nCurrentDataSetIndex < 0 ||
m_nCurrentDataSetIndex >= m_vecDataSets.size()) {
return;
}
removeMarkerByName(markerNameAt(row));
if(pointIndex < m_vecDataSets[m_nCurrentDataSetIndex].points.size()) {
m_vecDataSets[m_nCurrentDataSetIndex].points.remove(pointIndex);
}
if(pointIndex < m_vecMarkerNames[m_nCurrentDataSetIndex].size()) {
m_vecMarkerNames[m_nCurrentDataSetIndex].removeAt(pointIndex);
}
m_pPointTable->removeRow(row);
updatePointRowNumbers();
clearTableSelection();
updatePointButtons();
syncDataSetsToManager(true);
schedulePreviewRefresh();
}
void nmWxPropertyInterpolationDlg::onClearPoints()
{
if(m_nCurrentDataSetIndex < 0 ||
m_nCurrentDataSetIndex >= m_vecDataSets.size()) {
return;
}
removeDataSetMarkers(m_nCurrentDataSetIndex);
m_vecDataSets[m_nCurrentDataSetIndex].points.clear();
clearPointRows();
clearTableSelection();
updatePointButtons();
syncDataSetsToManager(true);
schedulePreviewRefresh();
}
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);
schedulePreviewRefresh();
}
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);
schedulePreviewRefresh();
}
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();
const bool hasPoints = hasCurrent &&
!m_vecDataSets[m_nCurrentDataSetIndex].points.isEmpty();
// 已有测点的数值含义已经确定,需清空测点后才能切换数据组属性.
m_pPropertyCombo->setEnabled(hasCurrent && !hasPoints);
m_pPropertyCombo->setToolTip(hasPoints ?
interpolationText("Clear measurement points before changing the property.") :
QString());
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);
}
void nmWxPropertyInterpolationDlg::onPreview()
{
if(m_pPreviewRefreshTimer != NULL) {
m_pPreviewRefreshTimer->stop();
}
updatePreviewWindow(true);
}
void nmWxPropertyInterpolationDlg::schedulePreviewRefresh()
{
if(m_pPreviewDialog.isNull() || !m_pPreviewDialog->isVisible() ||
m_pPreviewRefreshTimer == NULL) {
return;
}
// 连续编辑参数时重置计时,仅对最终状态执行一次插值计算.
m_pPreviewRefreshTimer->start();
}
void nmWxPropertyInterpolationDlg::refreshPreview()
{
if(m_pPreviewDialog.isNull() || !m_pPreviewDialog->isVisible()) {
return;
}
updatePreviewWindow(false);
}
void nmWxPropertyInterpolationDlg::showPreviewError(
const QString& message,
bool activateWindow)
{
const QString errorText = message.isEmpty() ?
interpolationText("Preview Failed") : message;
QString dataSetName;
if(m_nCurrentDataSetIndex >= 0 &&
m_nCurrentDataSetIndex < m_vecDataSets.size()) {
dataSetName = m_vecDataSets[m_nCurrentDataSetIndex].name;
}
if(!m_pPreviewDialog.isNull()) {
m_pPreviewDialog->showMessage(dataSetName, errorText);
if(activateWindow) {
m_pPreviewDialog->show();
m_pPreviewDialog->raise();
m_pPreviewDialog->activateWindow();
}
}
else if(activateWindow) {
QMessageBox::warning(this, interpolationText("Preview Failed"), errorText);
}
}
void nmWxPropertyInterpolationDlg::updatePreviewWindow(bool activateWindow)
{
if(m_nCurrentDataSetIndex < 0 ||
m_nCurrentDataSetIndex >= m_vecDataSets.size() ||
m_pDataManager.isNull()) {
showPreviewError(interpolationText("Preview Failed"), activateWindow);
return;
}
saveCurrentDataSet();
const nmPropertyInterpolationDataSet& dataSet =
m_vecDataSets[m_nCurrentDataSetIndex];
// 预览范围直接使用储层边界,与地图中的数据坐标保持一致.
QVector<QPointF> outlinePoints;
QRectF previewBounds;
if(!createPreviewOutline(m_pDataManager->getOutlineData(),
outlinePoints, previewBounds)) {
showPreviewError(
interpolationText("Please create a valid reservoir boundary before previewing."),
activateWindow);
return;
}
QVector<QPointF> measurementPoints;
QVector<double> measurementValues;
measurementPoints.reserve(dataSet.points.size());
measurementValues.reserve(dataSet.points.size());
for(int i = 0; i < dataSet.points.size(); ++i) {
measurementPoints.append(QPointF(dataSet.points[i].x,
dataSet.points[i].y));
measurementValues.append(dataSet.points[i].value);
}
// 按行生成规则待插值点,输出下标与预览网格下标保持一致;
// 较疏采样可使分级色带边界更清晰.
const int columnCount = 19;
const int rowCount = 19;
QVector<QPointF> targetPoints;
targetPoints.reserve(columnCount * rowCount);
for(int row = 0; row < rowCount; ++row) {
const double y = previewBounds.top() +
previewBounds.height() * row / (rowCount - 1);
for(int column = 0; column < columnCount; ++column) {
const double x = previewBounds.left() +
previewBounds.width() * column / (columnCount - 1);
targetPoints.append(QPointF(x, y));
}
}
QVector<double> interpolationValues;
QString errorMessage;
QApplication::setOverrideCursor(Qt::WaitCursor);
// 通过统一封装调用Kriging接口返回值顺序与待插值点一致.
const bool calculationSucceeded = nmCalculationUtils::calculateKriging(
targetPoints,
measurementPoints,
measurementValues,
dataSet.nugget,
dataSet.sill,
dataSet.range,
dataSet.model,
m_pDataManager->getLicensePath(),
interpolationValues,
&errorMessage);
QApplication::restoreOverrideCursor();
if(!calculationSucceeded) {
showPreviewError(errorMessage, activateWindow);
return;
}
// Kriging使用内部基准值渲染前统一转换表面和测点的显示单位.
const QString valueBaseUnit = propertyBaseUnit(dataSet.property);
QVector<double> displayInterpolationValues;
displayInterpolationValues.reserve(interpolationValues.size());
for(int i = 0; i < interpolationValues.size(); ++i) {
displayInterpolationValues.append(convertedUnitValue(
interpolationValues[i],
valueBaseUnit,
dataSet.valueDisplayUnit));
}
QVector<double> 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);
}
// 直接读取Map中实际显示的井避免“参与计算井”尚未设置时预览中没有井位.
QVector<QPointF> wellPoints;
QStringList wellNames;
const QVector<nmObjPointWell*> wellPlots = m_pPlot.isNull() ?
QVector<nmObjPointWell*>() : m_pPlot->getWellPlots();
for(int i = 0; i < wellPlots.size(); ++i) {
nmObjPointWell* wellPlot = wellPlots[i];
if(wellPlot == NULL || wellPlot->getWellData() == NULL) {
continue;
}
const QVector<double> wellInformation = wellPlot->getWellInformation();
const QString wellName = wellPlot->getWellData()->getName();
if(wellInformation.size() < 2 || wellName.isEmpty() ||
wellNames.contains(wellName)) {
continue;
}
const QPointF wellPoint(wellInformation[0], wellInformation[1]);
if(previewBounds.contains(wellPoint)) {
wellPoints.append(wellPoint);
wellNames.append(wellName);
}
}
// 预览窗口只负责裁剪和渲染,不修改数据组及正式求解参数.
if(m_pPreviewDialog.isNull()) {
m_pPreviewDialog = new nmWxPropertyInterpolationPreviewDlg(
dataSet.name,
scalarTitle,
previewBounds,
columnCount,
rowCount,
displayInterpolationValues,
measurementPoints,
displayMeasurementValues,
outlinePoints,
wellPoints,
wellNames,
dataSet.showPoints,
dataSet.showLabels,
this);
m_pPreviewDialog->setAttribute(Qt::WA_DeleteOnClose, true);
}
else {
m_pPreviewDialog->updatePreview(
dataSet.name,
scalarTitle,
previewBounds,
columnCount,
rowCount,
displayInterpolationValues,
measurementPoints,
displayMeasurementValues,
outlinePoints,
wellPoints,
wellNames,
dataSet.showPoints,
dataSet.showLabels);
}
if(activateWindow) {
m_pPreviewDialog->show();
m_pPreviewDialog->raise();
m_pPreviewDialog->activateWindow();
}
}
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();
}
}