|
|
|
|
|
#include "nmWellPressureFlowPage.h"
|
|
|
|
|
|
|
|
|
|
|
|
#include "iUnitGroup.h"
|
|
|
|
|
|
#include "iUnitHelper.h"
|
|
|
|
|
|
#include "iUnitItem.h"
|
|
|
|
|
|
#include "nmDataWellBase.h"
|
|
|
|
|
|
#include "nmWxPressFlowChartWidget.h"
|
|
|
|
|
|
#include "ZxBaseUtil.h"
|
|
|
|
|
|
#include "ZxTableHeaderViewUnit.h"
|
|
|
|
|
|
|
|
|
|
|
|
#include <QAbstractItemView>
|
|
|
|
|
|
#include <QHeaderView>
|
|
|
|
|
|
#include <QLabel>
|
|
|
|
|
|
#include <QList>
|
|
|
|
|
|
#include <QPalette>
|
|
|
|
|
|
#include <QSplitter>
|
|
|
|
|
|
#include <QStackedWidget>
|
|
|
|
|
|
#include <QStringList>
|
|
|
|
|
|
#include <QTableWidget>
|
|
|
|
|
|
#include <QTableWidgetItem>
|
|
|
|
|
|
#include <QVBoxLayout>
|
|
|
|
|
|
|
|
|
|
|
|
namespace
|
|
|
|
|
|
{
|
|
|
|
|
|
QString preferredTimeUnit()
|
|
|
|
|
|
{
|
|
|
|
|
|
return QLatin1String("h");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QString preferredFlowUnit()
|
|
|
|
|
|
{
|
|
|
|
|
|
return QString::fromUtf8("m\xC2\xB3/d");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
iUnitGroup* resolveUnitGroup(const QStringList& listCandidates,
|
|
|
|
|
|
QString& sResolvedUnit)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (int nIndex = 0; nIndex < listCandidates.size(); ++nIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
const QString& sCandidate = listCandidates[nIndex];
|
|
|
|
|
|
iUnitGroup* pUnitGroup =
|
|
|
|
|
|
iUnitHelper::getUnitGroupByUnit(sCandidate);
|
|
|
|
|
|
if (pUnitGroup == nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int nUnitIndex = pUnitGroup->indexOf(sCandidate);
|
|
|
|
|
|
QStringList listUnitNames = pUnitGroup->getAllUnitNames();
|
|
|
|
|
|
if (nUnitIndex < 0 || nUnitIndex >= listUnitNames.size())
|
|
|
|
|
|
{
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
sResolvedUnit = listUnitNames[nUnitIndex];
|
|
|
|
|
|
return pUnitGroup;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
sResolvedUnit = listCandidates.isEmpty()
|
|
|
|
|
|
? QString() : listCandidates.first();
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QLabel* createEmptyLabel(const QString& sText, QWidget* pParent)
|
|
|
|
|
|
{
|
|
|
|
|
|
QLabel* pLabel = new QLabel(sText, pParent);
|
|
|
|
|
|
pLabel->setAlignment(Qt::AlignCenter);
|
|
|
|
|
|
QPalette oPalette = pLabel->palette();
|
|
|
|
|
|
oPalette.setColor(QPalette::WindowText,
|
|
|
|
|
|
pParent->palette().color(QPalette::Mid));
|
|
|
|
|
|
pLabel->setPalette(oPalette);
|
|
|
|
|
|
return pLabel;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QString displayValueText(double dValue, int nDigit)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (nDigit <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
return QString::number(dValue, 'f', 0);
|
|
|
|
|
|
}
|
|
|
|
|
|
return ZxBaseUtil::getValidStr(dValue, nDigit);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nmWellPressureFlowPage::nmWellPressureFlowPage(QWidget* pParent)
|
|
|
|
|
|
: QWidget(pParent),
|
|
|
|
|
|
m_pWell(nullptr),
|
|
|
|
|
|
m_pContentStack(nullptr),
|
|
|
|
|
|
m_pHorizontalSplitter(nullptr),
|
|
|
|
|
|
m_pChartSplitter(nullptr),
|
|
|
|
|
|
m_pPressureChartStack(nullptr),
|
|
|
|
|
|
m_pFlowChartStack(nullptr),
|
|
|
|
|
|
m_pFlowTableStack(nullptr),
|
|
|
|
|
|
m_pPressureChart(nullptr),
|
|
|
|
|
|
m_pFlowChart(nullptr),
|
|
|
|
|
|
m_pFlowTable(nullptr),
|
|
|
|
|
|
m_pFlowHeader(nullptr),
|
|
|
|
|
|
m_pTimeUnitGroup(nullptr),
|
|
|
|
|
|
m_pFlowUnitGroup(nullptr),
|
|
|
|
|
|
m_sTimeBaseUnit(preferredTimeUnit()),
|
|
|
|
|
|
m_sFlowBaseUnit(preferredFlowUnit()),
|
|
|
|
|
|
m_sTimeUnit(preferredTimeUnit()),
|
|
|
|
|
|
m_sFlowUnit(preferredFlowUnit()),
|
|
|
|
|
|
m_nTimeDigit(6),
|
|
|
|
|
|
m_nFlowDigit(6),
|
|
|
|
|
|
m_nSelectedFlowSegment(-1)
|
|
|
|
|
|
{
|
|
|
|
|
|
createUi();
|
|
|
|
|
|
initializeUnitSupport();
|
|
|
|
|
|
resetDataViews();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void nmWellPressureFlowPage::setWell(nmDataWellBase* pWell)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (m_pWell == pWell)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
m_pWell = pWell;
|
|
|
|
|
|
resetDataViews();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void nmWellPressureFlowPage::refreshData()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (m_pWell == nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
resetDataViews();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 第一步:井数据只复制到页面基准副本,后续显示换算不会回写井对象。
|
|
|
|
|
|
QVector<QPointF> vecRawPressurePoints =
|
|
|
|
|
|
m_pWell->getPressurePoints();
|
|
|
|
|
|
QVector<QPointF> vecRawFlowPoints = m_pWell->getFlowPoints();
|
|
|
|
|
|
|
|
|
|
|
|
// 第二步:单位服务可能晚于页面构造完成,再刷新一次可用单位组。
|
|
|
|
|
|
initializeUnitSupport();
|
|
|
|
|
|
|
|
|
|
|
|
m_vecRawPressurePoints = vecRawPressurePoints;
|
|
|
|
|
|
m_vecRawFlowPoints = vecRawFlowPoints;
|
|
|
|
|
|
|
|
|
|
|
|
QVector<QPointF> vecTableFlowPoints;
|
|
|
|
|
|
int nTimeDigit = m_nTimeDigit;
|
|
|
|
|
|
int nFlowDigit = m_nFlowDigit;
|
|
|
|
|
|
if (!buildFlowTableData(m_sTimeUnit,
|
|
|
|
|
|
m_sFlowUnit,
|
|
|
|
|
|
vecTableFlowPoints,
|
|
|
|
|
|
nTimeDigit,
|
|
|
|
|
|
nFlowDigit))
|
|
|
|
|
|
{
|
|
|
|
|
|
// 当前显示单位不可用时回退基准单位,禁止继续展示旧井快照。
|
|
|
|
|
|
m_sTimeUnit = m_sTimeBaseUnit;
|
|
|
|
|
|
m_sFlowUnit = m_sFlowBaseUnit;
|
|
|
|
|
|
if (!buildFlowTableData(m_sTimeUnit,
|
|
|
|
|
|
m_sFlowUnit,
|
|
|
|
|
|
vecTableFlowPoints,
|
|
|
|
|
|
nTimeDigit,
|
|
|
|
|
|
nFlowDigit))
|
|
|
|
|
|
{
|
|
|
|
|
|
resetDataViews();
|
|
|
|
|
|
updateUnitHeader();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 第三步:换算与精度读取全部成功后再提交,曲线始终读取原始数据。
|
|
|
|
|
|
m_vecTableFlowPoints = vecTableFlowPoints;
|
|
|
|
|
|
m_nTimeDigit = nTimeDigit;
|
|
|
|
|
|
m_nFlowDigit = nFlowDigit;
|
|
|
|
|
|
updateUnitHeader();
|
|
|
|
|
|
updateViews();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void nmWellPressureFlowPage::clearData()
|
|
|
|
|
|
{
|
|
|
|
|
|
m_pWell = nullptr;
|
|
|
|
|
|
resetDataViews();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void nmWellPressureFlowPage::slotUnitChanged(
|
|
|
|
|
|
int nColumn,
|
|
|
|
|
|
const iUnitItem* pSourceUnit,
|
|
|
|
|
|
const iUnitItem* pDestinationUnit)
|
|
|
|
|
|
{
|
|
|
|
|
|
Q_UNUSED(pSourceUnit);
|
|
|
|
|
|
if (pDestinationUnit == nullptr ||
|
|
|
|
|
|
(nColumn != 0 && nColumn != 1))
|
|
|
|
|
|
{
|
|
|
|
|
|
updateUnitHeader();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QString sTimeUnit = m_sTimeUnit;
|
|
|
|
|
|
QString sFlowUnit = m_sFlowUnit;
|
|
|
|
|
|
if (nColumn == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (m_pTimeUnitGroup == nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
updateUnitHeader();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
sTimeUnit = pDestinationUnit->m_sName;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
if (m_pFlowUnitGroup == nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
updateUnitHeader();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
sFlowUnit = pDestinationUnit->m_sName;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 每次都从基准副本换算,禁止使用当前显示值继续换算。
|
|
|
|
|
|
QVector<QPointF> vecTableFlowPoints;
|
|
|
|
|
|
int nTimeDigit = m_nTimeDigit;
|
|
|
|
|
|
int nFlowDigit = m_nFlowDigit;
|
|
|
|
|
|
if (!buildFlowTableData(sTimeUnit,
|
|
|
|
|
|
sFlowUnit,
|
|
|
|
|
|
vecTableFlowPoints,
|
|
|
|
|
|
nTimeDigit,
|
|
|
|
|
|
nFlowDigit))
|
|
|
|
|
|
{
|
|
|
|
|
|
updateUnitHeader();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
m_sTimeUnit = sTimeUnit;
|
|
|
|
|
|
m_sFlowUnit = sFlowUnit;
|
|
|
|
|
|
m_vecTableFlowPoints = vecTableFlowPoints;
|
|
|
|
|
|
m_nTimeDigit = nTimeDigit;
|
|
|
|
|
|
m_nFlowDigit = nFlowDigit;
|
|
|
|
|
|
updateUnitHeader();
|
|
|
|
|
|
updateFlowTable();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void nmWellPressureFlowPage::slotFlowRowChanged(
|
|
|
|
|
|
int nCurrentRow,
|
|
|
|
|
|
int nCurrentColumn,
|
|
|
|
|
|
int nPreviousRow,
|
|
|
|
|
|
int nPreviousColumn)
|
|
|
|
|
|
{
|
|
|
|
|
|
Q_UNUSED(nCurrentColumn);
|
|
|
|
|
|
Q_UNUSED(nPreviousRow);
|
|
|
|
|
|
Q_UNUSED(nPreviousColumn);
|
|
|
|
|
|
|
|
|
|
|
|
applyFlowSegmentSelection(nCurrentRow);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void nmWellPressureFlowPage::slotFlowChartPointClicked(double dTimePoint)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 曲线保持基准单位,点击时间先换算为表格当前单位再定位行。
|
|
|
|
|
|
double dTableTimePoint = 0.0;
|
|
|
|
|
|
if (!convertValue(m_pTimeUnitGroup,
|
|
|
|
|
|
m_sTimeBaseUnit,
|
|
|
|
|
|
m_sTimeUnit,
|
|
|
|
|
|
dTimePoint,
|
|
|
|
|
|
dTableTimePoint))
|
|
|
|
|
|
{
|
|
|
|
|
|
applyFlowSegmentSelection(-1);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
applyFlowSegmentSelection(
|
|
|
|
|
|
findFlowSegmentByTableTime(dTableTimePoint));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void nmWellPressureFlowPage::createUi()
|
|
|
|
|
|
{
|
|
|
|
|
|
QVBoxLayout* pMainLayout = new QVBoxLayout(this);
|
|
|
|
|
|
pMainLayout->setContentsMargins(8, 6, 8, 8);
|
|
|
|
|
|
pMainLayout->setSpacing(0);
|
|
|
|
|
|
|
|
|
|
|
|
m_pContentStack = new QStackedWidget(this);
|
|
|
|
|
|
m_pHorizontalSplitter = new QSplitter(
|
|
|
|
|
|
Qt::Horizontal, m_pContentStack);
|
|
|
|
|
|
m_pHorizontalSplitter->setChildrenCollapsible(false);
|
|
|
|
|
|
|
|
|
|
|
|
// 左侧上下两图共享时间范围,但各自保留独立空状态。
|
|
|
|
|
|
m_pChartSplitter = new QSplitter(
|
|
|
|
|
|
Qt::Vertical, m_pHorizontalSplitter);
|
|
|
|
|
|
m_pChartSplitter->setChildrenCollapsible(false);
|
|
|
|
|
|
|
|
|
|
|
|
m_pPressureChartStack = new QStackedWidget(m_pChartSplitter);
|
|
|
|
|
|
m_pPressureChart = new nmWxPressFlowChartWidget(
|
|
|
|
|
|
m_pPressureChartStack);
|
|
|
|
|
|
m_pPressureChart->setReadOnly(true);
|
|
|
|
|
|
m_pPressureChart->setTimeSelectionEnabled(false);
|
|
|
|
|
|
m_pPressureChart->setAxisLabels(tr("Time"), tr("Pressure"));
|
|
|
|
|
|
m_pPressureChart->setAxisUnits(
|
|
|
|
|
|
m_sTimeBaseUnit, tr("MPa"));
|
|
|
|
|
|
m_pPressureChart->setLineColor(QColor(50, 200, 50));
|
|
|
|
|
|
m_pPressureChart->setChartType(CHART_TYPE_LINE);
|
|
|
|
|
|
m_pPressureChartStack->addWidget(m_pPressureChart);
|
|
|
|
|
|
m_pPressureChartStack->addWidget(createEmptyLabel(
|
|
|
|
|
|
tr("No pressure data"), m_pPressureChartStack));
|
|
|
|
|
|
|
|
|
|
|
|
m_pFlowChartStack = new QStackedWidget(m_pChartSplitter);
|
|
|
|
|
|
m_pFlowChart = new nmWxPressFlowChartWidget(m_pFlowChartStack);
|
|
|
|
|
|
m_pFlowChart->setReadOnly(true);
|
|
|
|
|
|
m_pFlowChart->setTimeSelectionEnabled(true);
|
|
|
|
|
|
m_pFlowChart->setAxisLabels(tr("Time"), tr("Flow"));
|
|
|
|
|
|
m_pFlowChart->setAxisUnits(m_sTimeBaseUnit, m_sFlowBaseUnit);
|
|
|
|
|
|
m_pFlowChart->setLineColor(QColor(255, 0, 0));
|
|
|
|
|
|
m_pFlowChart->setChartType(CHART_TYPE_STEP);
|
|
|
|
|
|
m_pFlowChartStack->addWidget(m_pFlowChart);
|
|
|
|
|
|
m_pFlowChartStack->addWidget(createEmptyLabel(
|
|
|
|
|
|
tr("No flow data"), m_pFlowChartStack));
|
|
|
|
|
|
|
|
|
|
|
|
m_pChartSplitter->addWidget(m_pPressureChartStack);
|
|
|
|
|
|
m_pChartSplitter->addWidget(m_pFlowChartStack);
|
|
|
|
|
|
m_pChartSplitter->setStretchFactor(0, 1);
|
|
|
|
|
|
m_pChartSplitter->setStretchFactor(1, 1);
|
|
|
|
|
|
|
|
|
|
|
|
// 右侧仅显示原始流量段对应的时间和流量,不提供任何编辑入口。
|
|
|
|
|
|
m_pFlowTableStack = new QStackedWidget(m_pHorizontalSplitter);
|
|
|
|
|
|
m_pFlowTable = new QTableWidget(m_pFlowTableStack);
|
|
|
|
|
|
m_pFlowTable->setColumnCount(2);
|
|
|
|
|
|
m_pFlowTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
|
|
|
|
|
m_pFlowTable->setSelectionBehavior(QAbstractItemView::SelectRows);
|
|
|
|
|
|
m_pFlowTable->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
|
|
|
|
m_pFlowTable->setSortingEnabled(false);
|
|
|
|
|
|
m_pFlowTable->setDragEnabled(false);
|
|
|
|
|
|
m_pFlowTable->setAcceptDrops(false);
|
|
|
|
|
|
m_pFlowTable->setDropIndicatorShown(false);
|
|
|
|
|
|
m_pFlowTable->setAlternatingRowColors(true);
|
|
|
|
|
|
m_pFlowTable->setStyleSheet(
|
|
|
|
|
|
"QTableWidget {"
|
|
|
|
|
|
" background-color: palette(base);"
|
|
|
|
|
|
" alternate-background-color: rgb(232, 232, 232);"
|
|
|
|
|
|
" gridline-color: palette(midlight);"
|
|
|
|
|
|
" border: 1px solid palette(mid);"
|
|
|
|
|
|
"}"
|
|
|
|
|
|
"QHeaderView {"
|
|
|
|
|
|
" background-color: palette(button);"
|
|
|
|
|
|
" color: palette(button-text);"
|
|
|
|
|
|
"}"
|
|
|
|
|
|
"QHeaderView::section {"
|
|
|
|
|
|
" background-color: palette(button);"
|
|
|
|
|
|
" color: palette(button-text);"
|
|
|
|
|
|
" border: none;"
|
|
|
|
|
|
" border-right: 1px solid palette(mid);"
|
|
|
|
|
|
" border-bottom: 1px solid palette(mid);"
|
|
|
|
|
|
"}"
|
|
|
|
|
|
"QTableCornerButton::section {"
|
|
|
|
|
|
" background-color: palette(base);"
|
|
|
|
|
|
" border: none;"
|
|
|
|
|
|
" border-right: 1px solid palette(mid);"
|
|
|
|
|
|
" border-bottom: 1px solid palette(mid);"
|
|
|
|
|
|
"}");
|
|
|
|
|
|
|
|
|
|
|
|
m_pFlowHeader = new ZxTableHeaderViewUnit(m_pFlowTable);
|
|
|
|
|
|
m_pFlowTable->setHorizontalHeader(m_pFlowHeader);
|
|
|
|
|
|
m_pFlowTable->horizontalHeader()->setMovable(false);
|
|
|
|
|
|
m_pFlowTable->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
|
|
|
|
|
|
m_pFlowTable->verticalHeader()->setMovable(false);
|
|
|
|
|
|
m_pFlowTable->verticalHeader()->setDefaultAlignment(Qt::AlignCenter);
|
|
|
|
|
|
m_pFlowTable->verticalHeader()->setMinimumWidth(18);
|
|
|
|
|
|
|
|
|
|
|
|
m_pFlowTableStack->addWidget(m_pFlowTable);
|
|
|
|
|
|
m_pFlowTableStack->addWidget(createEmptyLabel(
|
|
|
|
|
|
tr("No flow data"), m_pFlowTableStack));
|
|
|
|
|
|
|
|
|
|
|
|
m_pHorizontalSplitter->addWidget(m_pChartSplitter);
|
|
|
|
|
|
m_pHorizontalSplitter->addWidget(m_pFlowTableStack);
|
|
|
|
|
|
m_pHorizontalSplitter->setStretchFactor(0, 7);
|
|
|
|
|
|
m_pHorizontalSplitter->setStretchFactor(1, 3);
|
|
|
|
|
|
QList<int> listHorizontalSizes;
|
|
|
|
|
|
listHorizontalSizes << 700 << 300;
|
|
|
|
|
|
m_pHorizontalSplitter->setSizes(listHorizontalSizes);
|
|
|
|
|
|
|
|
|
|
|
|
m_pContentStack->addWidget(m_pHorizontalSplitter);
|
|
|
|
|
|
m_pContentStack->addWidget(createEmptyLabel(
|
|
|
|
|
|
tr("No pressure or flow data"), m_pContentStack));
|
|
|
|
|
|
pMainLayout->addWidget(m_pContentStack, 1);
|
|
|
|
|
|
|
|
|
|
|
|
connect(m_pFlowHeader,
|
|
|
|
|
|
SIGNAL(sigCbxValueChanged(int,const iUnitItem*,const iUnitItem*)),
|
|
|
|
|
|
this,
|
|
|
|
|
|
SLOT(slotUnitChanged(int,const iUnitItem*,const iUnitItem*)));
|
|
|
|
|
|
connect(m_pFlowTable,
|
|
|
|
|
|
SIGNAL(currentCellChanged(int,int,int,int)),
|
|
|
|
|
|
this,
|
|
|
|
|
|
SLOT(slotFlowRowChanged(int,int,int,int)));
|
|
|
|
|
|
connect(m_pFlowChart,
|
|
|
|
|
|
SIGNAL(chartPointClicked(double)),
|
|
|
|
|
|
this,
|
|
|
|
|
|
SLOT(slotFlowChartPointClicked(double)));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void nmWellPressureFlowPage::initializeUnitSupport()
|
|
|
|
|
|
{
|
|
|
|
|
|
QStringList listTimeCandidates;
|
|
|
|
|
|
listTimeCandidates << preferredTimeUnit() << QLatin1String("hr");
|
|
|
|
|
|
QStringList listFlowCandidates;
|
|
|
|
|
|
listFlowCandidates << preferredFlowUnit()
|
|
|
|
|
|
<< QLatin1String("m^3/d")
|
|
|
|
|
|
<< QLatin1String("m^3/D");
|
|
|
|
|
|
|
|
|
|
|
|
// 优先使用当前单位包的h、m³/d;旧英文单位包自动兼容hr、m^3/d。
|
|
|
|
|
|
m_pTimeUnitGroup = resolveUnitGroup(
|
|
|
|
|
|
listTimeCandidates, m_sTimeBaseUnit);
|
|
|
|
|
|
m_pFlowUnitGroup = resolveUnitGroup(
|
|
|
|
|
|
listFlowCandidates, m_sFlowBaseUnit);
|
|
|
|
|
|
|
|
|
|
|
|
// 单位组缺失或当前单位不再存在时回退基准单位,入口由框架表头禁用。
|
|
|
|
|
|
if (m_pTimeUnitGroup == nullptr ||
|
|
|
|
|
|
m_pTimeUnitGroup->indexOf(m_sTimeUnit) < 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_sTimeUnit = m_sTimeBaseUnit;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (m_pFlowUnitGroup == nullptr ||
|
|
|
|
|
|
m_pFlowUnitGroup->indexOf(m_sFlowUnit) < 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_sFlowUnit = m_sFlowBaseUnit;
|
|
|
|
|
|
}
|
|
|
|
|
|
updateUnitHeader();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void nmWellPressureFlowPage::updateUnitHeader()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (m_pFlowHeader == nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QStringList listTitles;
|
|
|
|
|
|
listTitles << tr("Time") << tr("Flow");
|
|
|
|
|
|
QStringList listUnits;
|
|
|
|
|
|
listUnits << m_sTimeUnit << m_sFlowUnit;
|
|
|
|
|
|
m_pFlowHeader->setHeaderData(listTitles, listUnits);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool nmWellPressureFlowPage::buildFlowTableData(
|
|
|
|
|
|
const QString& sTimeUnit,
|
|
|
|
|
|
const QString& sFlowUnit,
|
|
|
|
|
|
QVector<QPointF>& vecFlowPoints,
|
|
|
|
|
|
int& nTimeDigit,
|
|
|
|
|
|
int& nFlowDigit) const
|
|
|
|
|
|
{
|
|
|
|
|
|
vecFlowPoints = m_vecRawFlowPoints;
|
|
|
|
|
|
|
|
|
|
|
|
// 空数据也必须验证目标单位,避免表头切换后留下不可用单位状态。
|
|
|
|
|
|
double dConvertedZero = 0.0;
|
|
|
|
|
|
if (!convertValue(m_pTimeUnitGroup,
|
|
|
|
|
|
m_sTimeBaseUnit,
|
|
|
|
|
|
sTimeUnit,
|
|
|
|
|
|
0.0,
|
|
|
|
|
|
dConvertedZero,
|
|
|
|
|
|
&nTimeDigit) ||
|
|
|
|
|
|
!convertValue(m_pFlowUnitGroup,
|
|
|
|
|
|
m_sFlowBaseUnit,
|
|
|
|
|
|
sFlowUnit,
|
|
|
|
|
|
0.0,
|
|
|
|
|
|
dConvertedZero,
|
|
|
|
|
|
&nFlowDigit))
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 表格每次从原始副本换算,禁止使用当前显示值继续换算。
|
|
|
|
|
|
for (int nIndex = 0; nIndex < vecFlowPoints.size(); ++nIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
double dDuration = 0.0;
|
|
|
|
|
|
double dFlow = 0.0;
|
|
|
|
|
|
if (!convertValue(m_pTimeUnitGroup,
|
|
|
|
|
|
m_sTimeBaseUnit,
|
|
|
|
|
|
sTimeUnit,
|
|
|
|
|
|
m_vecRawFlowPoints[nIndex].x(),
|
|
|
|
|
|
dDuration) ||
|
|
|
|
|
|
!convertValue(m_pFlowUnitGroup,
|
|
|
|
|
|
m_sFlowBaseUnit,
|
|
|
|
|
|
sFlowUnit,
|
|
|
|
|
|
m_vecRawFlowPoints[nIndex].y(),
|
|
|
|
|
|
dFlow))
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
vecFlowPoints[nIndex] = QPointF(dDuration, dFlow);
|
|
|
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool nmWellPressureFlowPage::convertValue(
|
|
|
|
|
|
iUnitGroup* pUnitGroup,
|
|
|
|
|
|
const QString& sBaseUnit,
|
|
|
|
|
|
const QString& sDestinationUnit,
|
|
|
|
|
|
double dSourceValue,
|
|
|
|
|
|
double& dDestinationValue,
|
|
|
|
|
|
int* pDestinationDigit) const
|
|
|
|
|
|
{
|
|
|
|
|
|
int nDigit = 6;
|
|
|
|
|
|
if (pUnitGroup != nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
iUnitItem* pUnitItem =
|
|
|
|
|
|
pUnitGroup->getUnitItem(sDestinationUnit);
|
|
|
|
|
|
if (pUnitItem != nullptr && pUnitItem->m_nDigit >= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
nDigit = pUnitItem->m_nDigit;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (sDestinationUnit == sBaseUnit)
|
|
|
|
|
|
{
|
|
|
|
|
|
dDestinationValue = dSourceValue;
|
|
|
|
|
|
if (pDestinationDigit != nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
*pDestinationDigit = nDigit;
|
|
|
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (pUnitGroup == nullptr ||
|
|
|
|
|
|
pUnitGroup->indexOf(sBaseUnit) < 0 ||
|
|
|
|
|
|
pUnitGroup->indexOf(sDestinationUnit) < 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int nFallbackDigit = nDigit;
|
|
|
|
|
|
bool bConverted = pUnitGroup->convert(sBaseUnit,
|
|
|
|
|
|
dSourceValue,
|
|
|
|
|
|
sDestinationUnit,
|
|
|
|
|
|
dDestinationValue,
|
|
|
|
|
|
nDigit);
|
|
|
|
|
|
if (bConverted && pDestinationDigit != nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
*pDestinationDigit = nDigit >= 0
|
|
|
|
|
|
? nDigit : nFallbackDigit;
|
|
|
|
|
|
}
|
|
|
|
|
|
return bConverted;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void nmWellPressureFlowPage::updateViews()
|
|
|
|
|
|
{
|
|
|
|
|
|
QVector<QPointF> vecFlowChartPoints = createFlowChartPoints();
|
|
|
|
|
|
m_pPressureChart->setAxisUnits(
|
|
|
|
|
|
m_sTimeBaseUnit, tr("MPa"));
|
|
|
|
|
|
m_pFlowChart->setAxisUnits(m_sTimeBaseUnit, m_sFlowBaseUnit);
|
|
|
|
|
|
m_pPressureChart->setData(m_vecRawPressurePoints);
|
|
|
|
|
|
m_pFlowChart->setData(vecFlowChartPoints);
|
|
|
|
|
|
updateXAxisRange(vecFlowChartPoints);
|
|
|
|
|
|
updateFlowTable();
|
|
|
|
|
|
|
|
|
|
|
|
bool bPressureEmpty = m_vecRawPressurePoints.isEmpty();
|
|
|
|
|
|
bool bFlowEmpty = m_vecRawFlowPoints.isEmpty();
|
|
|
|
|
|
m_pPressureChartStack->setCurrentIndex(bPressureEmpty ? 1 : 0);
|
|
|
|
|
|
m_pFlowChartStack->setCurrentIndex(bFlowEmpty ? 1 : 0);
|
|
|
|
|
|
m_pFlowTableStack->setCurrentIndex(bFlowEmpty ? 1 : 0);
|
|
|
|
|
|
m_pContentStack->setCurrentIndex(
|
|
|
|
|
|
bPressureEmpty && bFlowEmpty ? 1 : 0);
|
|
|
|
|
|
updateSelectedFlowSegment();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QVector<QPointF> nmWellPressureFlowPage::createFlowChartPoints() const
|
|
|
|
|
|
{
|
|
|
|
|
|
QVector<QPointF> vecChartPoints;
|
|
|
|
|
|
double dTotalTime = 0.0;
|
|
|
|
|
|
for (int nIndex = 0;
|
|
|
|
|
|
nIndex < m_vecRawFlowPoints.size();
|
|
|
|
|
|
++nIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
const QPointF& oSegment = m_vecRawFlowPoints[nIndex];
|
|
|
|
|
|
if (nIndex == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
vecChartPoints.append(QPointF(0.0, oSegment.y()));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
dTotalTime += oSegment.x();
|
|
|
|
|
|
vecChartPoints.append(QPointF(dTotalTime, oSegment.y()));
|
|
|
|
|
|
if (nIndex < m_vecRawFlowPoints.size() - 1 &&
|
|
|
|
|
|
qAbs(m_vecRawFlowPoints[nIndex + 1].y() -
|
|
|
|
|
|
oSegment.y()) > 1e-6)
|
|
|
|
|
|
{
|
|
|
|
|
|
vecChartPoints.append(QPointF(
|
|
|
|
|
|
dTotalTime,
|
|
|
|
|
|
m_vecRawFlowPoints[nIndex + 1].y()));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return vecChartPoints;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void nmWellPressureFlowPage::updateFlowTable()
|
|
|
|
|
|
{
|
|
|
|
|
|
bool bSignalsWereBlocked = m_pFlowTable->blockSignals(true);
|
|
|
|
|
|
m_pFlowTable->clearContents();
|
|
|
|
|
|
m_pFlowTable->setRowCount(m_vecTableFlowPoints.size());
|
|
|
|
|
|
|
|
|
|
|
|
// 纵向表头显示Qt默认的1~N序号,内部仍使用零基流量点索引。
|
|
|
|
|
|
for (int nIndex = 0;
|
|
|
|
|
|
nIndex < m_vecTableFlowPoints.size();
|
|
|
|
|
|
++nIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
QTableWidgetItem* pTimeItem = new QTableWidgetItem(
|
|
|
|
|
|
displayValueText(m_vecTableFlowPoints[nIndex].x(),
|
|
|
|
|
|
m_nTimeDigit));
|
|
|
|
|
|
pTimeItem->setTextAlignment(Qt::AlignCenter);
|
|
|
|
|
|
m_pFlowTable->setItem(nIndex, 0, pTimeItem);
|
|
|
|
|
|
|
|
|
|
|
|
QTableWidgetItem* pFlowItem = new QTableWidgetItem(
|
|
|
|
|
|
displayValueText(m_vecTableFlowPoints[nIndex].y(),
|
|
|
|
|
|
m_nFlowDigit));
|
|
|
|
|
|
pFlowItem->setTextAlignment(Qt::AlignCenter);
|
|
|
|
|
|
m_pFlowTable->setItem(nIndex, 1, pFlowItem);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (m_nSelectedFlowSegment >= 0 &&
|
|
|
|
|
|
m_nSelectedFlowSegment < m_pFlowTable->rowCount())
|
|
|
|
|
|
{
|
|
|
|
|
|
m_pFlowTable->setCurrentCell(m_nSelectedFlowSegment, 0);
|
|
|
|
|
|
m_pFlowTable->selectRow(m_nSelectedFlowSegment);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
m_nSelectedFlowSegment = -1;
|
|
|
|
|
|
m_pFlowTable->setCurrentCell(-1, -1);
|
|
|
|
|
|
m_pFlowTable->clearSelection();
|
|
|
|
|
|
}
|
|
|
|
|
|
m_pFlowTable->blockSignals(bSignalsWereBlocked);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void nmWellPressureFlowPage::updateXAxisRange(
|
|
|
|
|
|
const QVector<QPointF>& vecFlowChartPoints)
|
|
|
|
|
|
{
|
|
|
|
|
|
bool bHasRange = false;
|
|
|
|
|
|
double dMinimum = 0.0;
|
|
|
|
|
|
double dMaximum = 0.0;
|
|
|
|
|
|
|
|
|
|
|
|
for (int nIndex = 0;
|
|
|
|
|
|
nIndex < m_vecRawPressurePoints.size();
|
|
|
|
|
|
++nIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
double dTime = m_vecRawPressurePoints[nIndex].x();
|
|
|
|
|
|
dMinimum = bHasRange ? qMin(dMinimum, dTime) : dTime;
|
|
|
|
|
|
dMaximum = bHasRange ? qMax(dMaximum, dTime) : dTime;
|
|
|
|
|
|
bHasRange = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
for (int nIndex = 0; nIndex < vecFlowChartPoints.size(); ++nIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
double dTime = vecFlowChartPoints[nIndex].x();
|
|
|
|
|
|
dMinimum = bHasRange ? qMin(dMinimum, dTime) : dTime;
|
|
|
|
|
|
dMaximum = bHasRange ? qMax(dMaximum, dTime) : dTime;
|
|
|
|
|
|
bHasRange = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (bHasRange)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_pPressureChart->setXAxisRange(dMinimum, dMaximum);
|
|
|
|
|
|
m_pFlowChart->setXAxisRange(dMinimum, dMaximum);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
m_pPressureChart->clearXAxisRange();
|
|
|
|
|
|
m_pFlowChart->clearXAxisRange();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void nmWellPressureFlowPage::updateSelectedFlowSegment()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (m_nSelectedFlowSegment < 0 ||
|
|
|
|
|
|
m_nSelectedFlowSegment >= m_vecRawFlowPoints.size())
|
|
|
|
|
|
{
|
|
|
|
|
|
m_pPressureChart->clearHighlightedTimeRange();
|
|
|
|
|
|
m_pFlowChart->clearHighlightedTimeRange();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 流量点X值是持续时间,段区间必须从第0段开始逐段累加。
|
|
|
|
|
|
double dStartTime = 0.0;
|
|
|
|
|
|
for (int nIndex = 0;
|
|
|
|
|
|
nIndex < m_nSelectedFlowSegment;
|
|
|
|
|
|
++nIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
dStartTime += m_vecRawFlowPoints[nIndex].x();
|
|
|
|
|
|
}
|
|
|
|
|
|
double dEndTime = dStartTime +
|
|
|
|
|
|
m_vecRawFlowPoints[m_nSelectedFlowSegment].x();
|
|
|
|
|
|
|
|
|
|
|
|
m_pPressureChart->setHighlightedTimeRange(
|
|
|
|
|
|
dStartTime, dEndTime);
|
|
|
|
|
|
m_pFlowChart->setHighlightedTimeRange(dStartTime, dEndTime);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void nmWellPressureFlowPage::applyFlowSegmentSelection(int nSegmentIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (nSegmentIndex < 0 ||
|
|
|
|
|
|
nSegmentIndex >= m_vecRawFlowPoints.size() ||
|
|
|
|
|
|
nSegmentIndex >= m_pFlowTable->rowCount())
|
|
|
|
|
|
{
|
|
|
|
|
|
nSegmentIndex = -1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
m_nSelectedFlowSegment = nSegmentIndex;
|
|
|
|
|
|
bool bSignalsWereBlocked = m_pFlowTable->blockSignals(true);
|
|
|
|
|
|
if (m_nSelectedFlowSegment >= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_pFlowTable->setCurrentCell(m_nSelectedFlowSegment, 0);
|
|
|
|
|
|
m_pFlowTable->selectRow(m_nSelectedFlowSegment);
|
|
|
|
|
|
QTableWidgetItem* pItem = m_pFlowTable->item(
|
|
|
|
|
|
m_nSelectedFlowSegment, 0);
|
|
|
|
|
|
if (pItem != nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_pFlowTable->scrollToItem(
|
|
|
|
|
|
pItem, QAbstractItemView::EnsureVisible);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
m_pFlowTable->setCurrentCell(-1, -1);
|
|
|
|
|
|
m_pFlowTable->clearSelection();
|
|
|
|
|
|
}
|
|
|
|
|
|
m_pFlowTable->blockSignals(bSignalsWereBlocked);
|
|
|
|
|
|
updateSelectedFlowSegment();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int nmWellPressureFlowPage::findFlowSegmentByTableTime(
|
|
|
|
|
|
double dTimePoint) const
|
|
|
|
|
|
{
|
|
|
|
|
|
double dTotalTime = 0.0;
|
|
|
|
|
|
for (int nIndex = 0;
|
|
|
|
|
|
nIndex < m_vecTableFlowPoints.size();
|
|
|
|
|
|
++nIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
dTotalTime += qMax(0.0, m_vecTableFlowPoints[nIndex].x());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const double dTolerance = qMax(1.0, qAbs(dTotalTime)) * 1e-9;
|
|
|
|
|
|
if (dTimePoint < 0.0 ||
|
|
|
|
|
|
dTimePoint > dTotalTime + dTolerance)
|
|
|
|
|
|
{
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 零时长点不占区间;分界点继续查找后一有效段。
|
|
|
|
|
|
double dStartTime = 0.0;
|
|
|
|
|
|
int nLastValidSegment = -1;
|
|
|
|
|
|
for (int nIndex = 0;
|
|
|
|
|
|
nIndex < m_vecTableFlowPoints.size();
|
|
|
|
|
|
++nIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
double dDuration = m_vecTableFlowPoints[nIndex].x();
|
|
|
|
|
|
if (dDuration <= dTolerance)
|
|
|
|
|
|
{
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nLastValidSegment = nIndex;
|
|
|
|
|
|
double dEndTime = dStartTime + dDuration;
|
|
|
|
|
|
if (dTimePoint < dEndTime - dTolerance)
|
|
|
|
|
|
{
|
|
|
|
|
|
return nIndex;
|
|
|
|
|
|
}
|
|
|
|
|
|
dStartTime = dEndTime;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 最终结束点没有后一段,归入最后一个有效流量段。
|
|
|
|
|
|
if (nLastValidSegment >= 0 &&
|
|
|
|
|
|
qAbs(dTimePoint - dTotalTime) <= dTolerance)
|
|
|
|
|
|
{
|
|
|
|
|
|
return nLastValidSegment;
|
|
|
|
|
|
}
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void nmWellPressureFlowPage::resetDataViews()
|
|
|
|
|
|
{
|
|
|
|
|
|
m_vecRawPressurePoints.clear();
|
|
|
|
|
|
m_vecRawFlowPoints.clear();
|
|
|
|
|
|
m_vecTableFlowPoints.clear();
|
|
|
|
|
|
m_nSelectedFlowSegment = -1;
|
|
|
|
|
|
updateViews();
|
|
|
|
|
|
}
|