完善网格属性插值交互与预览显示

feature/Interpolation-20260803
lvjunjie 2 weeks ago
parent 5548533fdf
commit 18fda630a7

Binary file not shown.

@ -6642,21 +6642,25 @@ Average pressure in contour: %2 MPa</source>
<source>Show labels</source>
<translation></translation>
</message>
<message>
<source>Clear measurement points before changing the property.</source>
<translation></translation>
</message>
<message>
<source>Kriging Parameters</source>
<translation>Kriging</translation>
<translation></translation>
</message>
<message>
<source>Nugget:</source>
<translation>Nugget</translation>
<translation></translation>
</message>
<message>
<source>Sill:</source>
<translation>Sill</translation>
<translation></translation>
</message>
<message>
<source>Range:</source>
<translation>Range</translation>
<translation></translation>
</message>
<message>
<source>Model:</source>
@ -6682,10 +6686,6 @@ Average pressure in contour: %2 MPa</source>
<source>Preview</source>
<translation></translation>
</message>
<message>
<source>Apply</source>
<translation></translation>
</message>
<message>
<source>Close</source>
<translation></translation>

@ -74,6 +74,7 @@ private:
void updateUnitControls(nmPropertyInterpolationDataSet& dataSet);
void updatePointDisplayValues();
void clearPointRows();
void updatePointRowNumbers();
void syncDataSetsToManager(bool markModified);
void updateDataSetButtons();
// 管理正式求解时k、phi和h各自使用的插值数据组.
@ -157,9 +158,8 @@ private:
QCheckBox* m_pUseHCheck;
QComboBox* m_pHCalculationDataSetCombo;
// 结果预览及应用.
// 插值结果预览.
QPushButton* m_pPreviewButton;
QPushButton* m_pApplyButton;
QPointer<nmWxPropertyInterpolationPreviewDlg> m_pPreviewDialog;
QTimer* m_pPreviewRefreshTimer;
};

@ -7,6 +7,7 @@
#include <QPointF>
#include <QRectF>
#include <QString>
#include <QStringList>
#include <QVector>
class QVTKWidget;
@ -25,6 +26,8 @@ public:
const QVector<QPointF>& measurementPoints,
const QVector<double>& measurementValues,
const QVector<QPointF>& outlinePoints,
const QVector<QPointF>& wellPoints,
const QStringList& wellNames,
bool showMeasurementPoints,
bool showMeasurementLabels,
QWidget* parent = 0);
@ -38,6 +41,8 @@ public:
const QVector<QPointF>& measurementPoints,
const QVector<double>& measurementValues,
const QVector<QPointF>& outlinePoints,
const QVector<QPointF>& wellPoints,
const QStringList& wellNames,
bool showMeasurementPoints,
bool showMeasurementLabels);
void showMessage(const QString& dataSetName, const QString& message);
@ -51,6 +56,8 @@ private:
const QVector<QPointF>& measurementPoints,
const QVector<double>& measurementValues,
const QVector<QPointF>& outlinePoints,
const QVector<QPointF>& wellPoints,
const QStringList& wellNames,
bool showMeasurementPoints,
bool showMeasurementLabels);

@ -33,10 +33,12 @@
#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"
@ -336,15 +338,14 @@ nmWxPropertyInterpolationDlg::nmWxPropertyInterpolationDlg(
m_pUseHCheck(NULL),
m_pHCalculationDataSetCombo(NULL),
m_pPreviewButton(NULL),
m_pApplyButton(NULL),
m_pPreviewDialog(NULL),
m_pPreviewRefreshTimer(NULL)
{
setWindowTitle(interpolationText("Property Interpolation"));
setWindowModality(Qt::NonModal);
setModal(false);
setMinimumSize(520, 680);
resize(560, 740);
setMinimumSize(600, 620);
resize(640, 680);
// 合并连续编辑触发的刷新,避免每次数值变化都立即重新插值.
m_pPreviewRefreshTimer = new QTimer(this);
@ -375,38 +376,52 @@ nmWxPropertyInterpolationDlg::~nmWxPropertyInterpolationDlg()
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);
// 数据组创建、切换及删除.
QHBoxLayout* dataSetSelectLayout = new QHBoxLayout;
dataSetSelectLayout->addWidget(new QLabel(interpolationText("Dataset:"), this));
m_pDataSetCombo = new QComboBox(this);
// 数据组、名称和属性共用一个表单,保证三行标签及输入控件对齐.
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(this);
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(this);
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);
mainLayout->addLayout(dataSetSelectLayout);
dataSetLayout->addRow(interpolationText("Dataset:"), dataSetSelectWidget);
// 当前数据组的名称和属性.
QFormLayout* dataSetLayout = new QFormLayout;
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"));
@ -416,17 +431,23 @@ void nmWxPropertyInterpolationDlg::initInterpolationUI()
// 测点数据录入区域.
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->setMinimumWidth(80);
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 &&
@ -438,11 +459,17 @@ void nmWxPropertyInterpolationDlg::initInterpolationUI()
QStringList headers;
headers << interpolationText("X") << interpolationText("Y") << interpolationText("Value");
m_pPointTable->setHorizontalHeaderLabels(headers);
m_pPointTable->verticalHeader()->setVisible(false);
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行开始.
@ -461,83 +488,99 @@ void nmWxPropertyInterpolationDlg::initInterpolationUI()
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);
QHBoxLayout* displayLayout = new QHBoxLayout;
m_pShowPointsCheck = new QCheckBox(interpolationText("Show measurement points"), pointGroup);
m_pShowPointsCheck->setChecked(true);
displayLayout->addWidget(m_pShowPointsCheck);
m_pShowLabelsCheck = new QCheckBox(interpolationText("Show labels"), pointGroup);
m_pShowLabelsCheck->setChecked(true);
displayLayout->addWidget(m_pShowLabelsCheck);
displayLayout->addStretch();
pointLayout->addLayout(displayLayout);
mainLayout->addWidget(pointGroup, 1);
// Kriging插值参数设置.
// Kriging参数采用两行双列布局保持信息完整并压缩纵向空间.
QGroupBox* parameterGroup = new QGroupBox(interpolationText("Kriging Parameters"), this);
QFormLayout* parameterLayout = new QFormLayout(parameterGroup);
QGridLayout* parameterLayout = new QGridLayout(parameterGroup);
parameterLayout->setContentsMargins(10, 8, 10, 10);
parameterLayout->setHorizontalSpacing(8);
parameterLayout->setVerticalSpacing(6);
m_pNuggetSpin = createNumberSpinBox(parameterGroup, 0.01);
parameterLayout->addRow(interpolationText("Nugget:"), m_pNuggetSpin);
parameterLayout->addWidget(new QLabel(interpolationText("Nugget:"), parameterGroup), 0, 0);
parameterLayout->addWidget(m_pNuggetSpin, 0, 1);
m_pSillSpin = createNumberSpinBox(parameterGroup, 100.0);
parameterLayout->addRow(interpolationText("Sill:"), m_pSillSpin);
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(parameterGroup, 1000.0);
m_pRangeSpin = createNumberSpinBox(rangeWidget, 1000.0);
rangeLayout->addWidget(m_pRangeSpin, 1);
m_pRangeUnitCombo = new QComboBox(parameterGroup);
m_pRangeUnitCombo->setMinimumWidth(80);
m_pRangeUnitCombo = new QComboBox(rangeWidget);
m_pRangeUnitCombo->setFixedWidth(72);
populateUnitCombo(m_pRangeUnitCombo, LENGTH_BASE_UNIT, LENGTH_BASE_UNIT);
rangeLayout->addWidget(m_pRangeUnitCombo);
parameterLayout->addRow(interpolationText("Range:"), rangeWidget);
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->addRow(interpolationText("Model:"), m_pModelCombo);
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->setColumnStretch(1, 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();
m_pApplyButton = new QPushButton(interpolationText("Apply"), this);
m_pApplyButton->setEnabled(false);
buttonLayout->addWidget(m_pApplyButton);
QPushButton* closeButton = new QPushButton(interpolationText("Close"), this);
closeButton->setMinimumWidth(84);
buttonLayout->addWidget(closeButton);
mainLayout->addLayout(buttonLayout);
@ -848,6 +891,28 @@ void nmWxPropertyInterpolationDlg::clearPointRows()
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)
@ -1277,6 +1342,9 @@ void nmWxPropertyInterpolationDlg::appendPointRow(
// 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;
@ -1294,14 +1362,12 @@ void nmWxPropertyInterpolationDlg::appendPointRow(
QTableWidgetItem* xItem = new QTableWidgetItem(displayValueText(
convertedUnitValue(point.x, LENGTH_BASE_UNIT, xUnit)));
xItem->setFlags(xItem->flags() & ~Qt::ItemIsEditable);
// 将地图标记名称绑定在X列后续可由表格行直接定位对应标记.
xItem->setData(Qt::UserRole, markerName);
m_pPointTable->setItem(row, 0, xItem);
QTableWidgetItem* yItem = new QTableWidgetItem(displayValueText(
convertedUnitValue(point.y, LENGTH_BASE_UNIT, yUnit)));
yItem->setFlags(yItem->flags() & ~Qt::ItemIsEditable);
m_pPointTable->setItem(row, 1, yItem);
m_pPointTable->setItem(row, 2, new QTableWidgetItem(displayValueText(
@ -1449,7 +1515,8 @@ void nmWxPropertyInterpolationDlg::onPointItemChanged(QTableWidgetItem* item)
// 表格行减去单位行偏移后,才是数据组中的测点下标.
const int pointIndex = item == NULL ? -1 :
item->row() - FIRST_POINT_ROW;
if(m_bUpdatingUi || item == NULL || item->column() != 2 ||
if(m_bUpdatingUi || item == NULL || item->column() < 0 ||
item->column() > 2 ||
pointIndex < 0 ||
m_nCurrentDataSetIndex < 0 ||
m_nCurrentDataSetIndex >= m_vecDataSets.size() ||
@ -1457,15 +1524,72 @@ void nmWxPropertyInterpolationDlg::onPointItemChanged(QTableWidgetItem* item)
return;
}
// 数值修改后同步更新数据组和地图标签,坐标列保持只读.
nmPropertyInterpolationDataSet& dataSet =
m_vecDataSets[m_nCurrentDataSetIndex];
dataSet.points[pointIndex].value = convertedUnitValue(
item->text().toDouble(), dataSet.valueDisplayUnit,
propertyBaseUnit(dataSet.property));
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) {
setMarkerLabel(marker, item->text());
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);
@ -1490,6 +1614,7 @@ void nmWxPropertyInterpolationDlg::onDeleteSelectedPoint()
m_vecMarkerNames[m_nCurrentDataSetIndex].removeAt(pointIndex);
}
m_pPointTable->removeRow(row);
updatePointRowNumbers();
clearTableSelection();
updatePointButtons();
syncDataSetsToManager(true);
@ -1548,6 +1673,14 @@ 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(
@ -1646,8 +1779,8 @@ void nmWxPropertyInterpolationDlg::updatePreviewWindow(bool activateWindow)
// 按行生成规则待插值点,输出下标与预览网格下标保持一致;
// 较疏采样可使分级色带边界更清晰.
const int columnCount = 31;
const int rowCount = 31;
const int columnCount = 19;
const int rowCount = 19;
QVector<QPointF> targetPoints;
targetPoints.reserve(columnCount * rowCount);
for(int row = 0; row < rowCount; ++row) {
@ -1705,6 +1838,31 @@ void nmWxPropertyInterpolationDlg::updatePreviewWindow(bool activateWindow)
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(
@ -1717,6 +1875,8 @@ void nmWxPropertyInterpolationDlg::updatePreviewWindow(bool activateWindow)
measurementPoints,
displayMeasurementValues,
outlinePoints,
wellPoints,
wellNames,
dataSet.showPoints,
dataSet.showLabels,
this);
@ -1733,6 +1893,8 @@ void nmWxPropertyInterpolationDlg::updatePreviewWindow(bool activateWindow)
measurementPoints,
displayMeasurementValues,
outlinePoints,
wellPoints,
wellNames,
dataSet.showPoints,
dataSet.showLabels);
}

@ -29,6 +29,7 @@
#include <vtkRenderer.h>
#include <vtkScalarBarActor.h>
#include <vtkSmartPointer.h>
#include <vtkStringArray.h>
#include <vtkTextActor.h>
#include <vtkTextProperty.h>
#include <vtkVertexGlyphFilter.h>
@ -85,6 +86,8 @@ nmWxPropertyInterpolationPreviewDlg::nmWxPropertyInterpolationPreviewDlg(
const QVector<QPointF>& measurementPoints,
const QVector<double>& measurementValues,
const QVector<QPointF>& outlinePoints,
const QVector<QPointF>& wellPoints,
const QStringList& wellNames,
bool showMeasurementPoints,
bool showMeasurementLabels,
QWidget* parent)
@ -113,7 +116,7 @@ nmWxPropertyInterpolationPreviewDlg::nmWxPropertyInterpolationPreviewDlg(
updatePreview(dataSetName, scalarTitle, bounds, columnCount, rowCount,
interpolationValues, measurementPoints,
measurementValues, outlinePoints,
measurementValues, outlinePoints, wellPoints, wellNames,
showMeasurementPoints, showMeasurementLabels);
}
@ -127,13 +130,15 @@ void nmWxPropertyInterpolationPreviewDlg::updatePreview(
const QVector<QPointF>& measurementPoints,
const QVector<double>& measurementValues,
const QVector<QPointF>& outlinePoints,
const QVector<QPointF>& wellPoints,
const QStringList& wellNames,
bool showMeasurementPoints,
bool showMeasurementLabels)
{
setWindowTitle(previewText("Interpolation Preview") + " - " + dataSetName);
initializeRenderer(scalarTitle, bounds, columnCount, rowCount,
interpolationValues, measurementPoints,
measurementValues, outlinePoints,
measurementValues, outlinePoints, wellPoints, wellNames,
showMeasurementPoints, showMeasurementLabels);
}
@ -171,6 +176,8 @@ void nmWxPropertyInterpolationPreviewDlg::initializeRenderer(
const QVector<QPointF>& measurementPoints,
const QVector<double>& measurementValues,
const QVector<QPointF>& outlinePoints,
const QVector<QPointF>& wellPoints,
const QStringList& wellNames,
bool showMeasurementPoints,
bool showMeasurementLabels)
{
@ -325,8 +332,8 @@ void nmWxPropertyInterpolationPreviewDlg::initializeRenderer(
vtkSmartPointer<vtkLookupTable> lookupTable =
createPreviewLookupTable(displayMinimum, displayMaximum);
// 将连续点标量划分为10级色带Mapper按CellData进行分级着色.
const int colorBandCount = 10;
// 将连续点标量划分为8级色带Mapper按CellData进行分级着色.
const int colorBandCount = 8;
vtkSmartPointer<vtkBandedPolyDataContourFilter> bandFilter =
vtkSmartPointer<vtkBandedPolyDataContourFilter>::New();
bandFilter->SetInputData(visibleSurface);
@ -439,9 +446,26 @@ void nmWxPropertyInterpolationPreviewDlg::initializeRenderer(
}
if(showMeasurementLabels) {
// 标签使用独立坐标上移,测点方框仍保持在原始测量位置.
const double labelOffset =
qMax(bounds.width(), bounds.height()) * 0.018;
vtkSmartPointer<vtkPoints> measurementLabelPoints =
vtkSmartPointer<vtkPoints>::New();
for(int i = 0; i < measurementPoints.size(); ++i) {
measurementLabelPoints->InsertNextPoint(
measurementPoints[i].x(),
measurementPoints[i].y() + labelOffset, 0.03);
}
vtkSmartPointer<vtkPolyData> measurementLabelData =
vtkSmartPointer<vtkPolyData>::New();
measurementLabelData->SetPoints(measurementLabelPoints);
measurementLabelData->GetPointData()->SetScalars(
measurementScalars);
vtkSmartPointer<vtkLabeledDataMapper> labelMapper =
vtkSmartPointer<vtkLabeledDataMapper>::New();
labelMapper->SetInputData(measurementData);
labelMapper->SetInputData(measurementLabelData);
labelMapper->SetLabelModeToLabelScalars();
labelMapper->SetLabelFormat("%.6g");
labelMapper->GetLabelTextProperty()->SetColor(0.12, 0.12, 0.12);
@ -449,15 +473,96 @@ void nmWxPropertyInterpolationPreviewDlg::initializeRenderer(
labelMapper->GetLabelTextProperty()->BoldOff();
labelMapper->GetLabelTextProperty()->ItalicOff();
labelMapper->GetLabelTextProperty()->ShadowOff();
labelMapper->GetLabelTextProperty()->SetJustificationToCentered();
labelMapper->GetLabelTextProperty()->SetVerticalJustificationToBottom();
vtkSmartPointer<vtkActor2D> labelActor =
vtkSmartPointer<vtkActor2D>::New();
labelActor->SetMapper(labelMapper);
labelActor->SetPosition(0.0, 10.0);
renderer->AddActor2D(labelActor);
}
}
// Map中显示的井使用独立红色标记和名称叠加不参与插值表面计算.
if(!wellPoints.isEmpty() && wellPoints.size() == wellNames.size()) {
vtkSmartPointer<vtkPoints> wellVtkPoints =
vtkSmartPointer<vtkPoints>::New();
vtkSmartPointer<vtkStringArray> wellNameArray =
vtkSmartPointer<vtkStringArray>::New();
wellNameArray->SetName("WellName");
for(int i = 0; i < wellPoints.size(); ++i) {
wellVtkPoints->InsertNextPoint(wellPoints[i].x(),
wellPoints[i].y(), 0.04);
wellNameArray->InsertNextValue(wellNames[i].toUtf8().constData());
}
vtkSmartPointer<vtkPolyData> wellData =
vtkSmartPointer<vtkPolyData>::New();
wellData->SetPoints(wellVtkPoints);
wellData->GetPointData()->AddArray(wellNameArray);
vtkSmartPointer<vtkVertexGlyphFilter> wellGlyphFilter =
vtkSmartPointer<vtkVertexGlyphFilter>::New();
wellGlyphFilter->SetInputData(wellData);
vtkSmartPointer<vtkPolyDataMapper> wellBorderMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
wellBorderMapper->SetInputConnection(wellGlyphFilter->GetOutputPort());
wellBorderMapper->ScalarVisibilityOff();
vtkSmartPointer<vtkActor> wellBorderActor =
vtkSmartPointer<vtkActor>::New();
wellBorderActor->SetMapper(wellBorderMapper);
wellBorderActor->GetProperty()->SetColor(0.12, 0.12, 0.12);
wellBorderActor->GetProperty()->SetPointSize(9.0);
renderer->AddActor(wellBorderActor);
vtkSmartPointer<vtkPolyDataMapper> wellMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
wellMapper->SetInputConnection(wellGlyphFilter->GetOutputPort());
wellMapper->ScalarVisibilityOff();
vtkSmartPointer<vtkActor> wellActor = vtkSmartPointer<vtkActor>::New();
wellActor->SetMapper(wellMapper);
wellActor->GetProperty()->SetColor(0.90, 0.12, 0.10);
wellActor->GetProperty()->SetPointSize(5.0);
wellActor->SetPosition(0.0, 0.0, 0.001);
renderer->AddActor(wellActor);
// 井名同样使用独立坐标,避免文字覆盖井位标记.
const double wellLabelOffset =
qMax(bounds.width(), bounds.height()) * 0.022;
vtkSmartPointer<vtkPoints> wellLabelPoints =
vtkSmartPointer<vtkPoints>::New();
for(int i = 0; i < wellPoints.size(); ++i) {
wellLabelPoints->InsertNextPoint(
wellPoints[i].x(),
wellPoints[i].y() + wellLabelOffset, 0.05);
}
vtkSmartPointer<vtkPolyData> wellLabelData =
vtkSmartPointer<vtkPolyData>::New();
wellLabelData->SetPoints(wellLabelPoints);
wellLabelData->GetPointData()->AddArray(wellNameArray);
vtkSmartPointer<vtkLabeledDataMapper> wellLabelMapper =
vtkSmartPointer<vtkLabeledDataMapper>::New();
wellLabelMapper->SetInputData(wellLabelData);
wellLabelMapper->SetLabelModeToLabelFieldData();
wellLabelMapper->SetFieldDataName("WellName");
wellLabelMapper->SetLabelFormat("%s");
wellLabelMapper->GetLabelTextProperty()->SetColor(0.10, 0.10, 0.10);
wellLabelMapper->GetLabelTextProperty()->SetFontSize(13);
wellLabelMapper->GetLabelTextProperty()->BoldOff();
wellLabelMapper->GetLabelTextProperty()->ItalicOff();
wellLabelMapper->GetLabelTextProperty()->ShadowOff();
wellLabelMapper->GetLabelTextProperty()->SetJustificationToCentered();
wellLabelMapper->GetLabelTextProperty()->SetVerticalJustificationToBottom();
vtkSmartPointer<vtkActor2D> wellLabelActor =
vtkSmartPointer<vtkActor2D>::New();
wellLabelActor->SetMapper(wellLabelMapper);
renderer->AddActor2D(wellLabelActor);
}
vtkSmartPointer<vtkScalarBarActor> scalarBar =
vtkSmartPointer<vtkScalarBarActor>::New();
scalarBar->SetLookupTable(lookupTable);

Loading…
Cancel
Save