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...

1954 lines
72 KiB
C++

#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保存渗透率统一以mD保存和显示。
const char* LENGTH_BASE_UNIT = "m";
const char* PERMEABILITY_BASE_UNIT = "mD";
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)
{
return 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);
// 合并连续编辑触发的刷新,避免每次数值变化都立即重新插值.
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/";
// 数据组操作按钮使用独立边框,便于识别可点击区域.
const QString dataSetButtonStyle =
"QPushButton {"
" border: 1px solid #aeb5bd;"
" border-radius: 3px;"
" background-color: #ffffff;"
" padding: 0px;"
"}"
"QPushButton:hover {"
" border-color: #6d9fc7;"
" background-color: #f5f9fc;"
"}"
"QPushButton:pressed {"
" background-color: #e8f1f8;"
"}"
"QPushButton:disabled {"
" border-color: #d6d9dc;"
" background-color: #f5f5f5;"
"}";
m_pAddDataSetButton = new QPushButton(dataSetSelectWidget);
m_pAddDataSetButton->setIcon(QIcon(iconDir + "Add.png"));
m_pAddDataSetButton->setIconSize(QSize(20, 20));
m_pAddDataSetButton->setFixedSize(34, 30);
m_pAddDataSetButton->setStyleSheet(dataSetButtonStyle);
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(20, 20));
m_pDeleteDataSetButton->setFixedSize(34, 30);
m_pDeleteDataSetButton->setStyleSheet(dataSetButtonStyle);
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();
}
}