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/nmWxMeasureDlg.cpp

255 lines
9.3 KiB
C++

#include "nmWxMeasureDlg.h"
#include "iUnitWxBinder.h"
#include "nmDataAnalyzeManager.h"
#include "nmDataMeasure.h"
#include "nmDataWellBase.h"
#include "nmGuiPlot.h"
#include "ZxBaseUtil.h"
#include <QComboBox>
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QLineF>
#include <QPushButton>
#include <QVBoxLayout>
#include <limits>
nmWxMeasureDlg::nmWxMeasureDlg(QWidget* parent)
: iDlgBase(parent),
m_pLengthEdit(nullptr),
m_pFitStartButton(nullptr),
m_pFitEndButton(nullptr),
m_bUnitBound(false)
{
// 浮动窗口必须绑定父级画布的分析,不能随全局当前页签变化而串用数据。
nmGuiPlot* pOwnerPlot = qobject_cast<nmGuiPlot*>(parent);
if (pOwnerPlot != nullptr)
{
m_pDataManager = pOwnerPlot->boundDataManager();
}
if (!m_pDataManager.isNull())
{
m_pData = m_pDataManager->getMeasureData();
}
initUI();
updateDisplay();
setWindowTitle(tr("Measure"));
// 保留浮动置顶行为,便于在绘图区连续测量,同时移除无帮助内容的问号按钮。
setWindowFlags((windowFlags() | Qt::WindowStaysOnTopHint) &
~Qt::WindowContextHelpButtonHint);
// 初始大小由字体、主题及布局推荐尺寸决定;adjustSize 同时考虑屏幕尺寸。
// 这里只设置初始大小,不限制用户之后调整窗口。
adjustSize();
}
void nmWxMeasureDlg::initUI()
{
// 与比例尺设置保持相同的外边距和分组间距,控件尺寸交给字体与主题计算。
QVBoxLayout* pMainLayout = new QVBoxLayout(this);
pMainLayout->setContentsMargins(12, 10, 12, 0);
pMainLayout->setSpacing(10);
QGroupBox* pGroup = new QGroupBox(tr("Measurement results"), this);
// 分组只横向伸展,内容高度由字体和主题的推荐尺寸决定,避免纵向拉长控件或行间距。
pGroup->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
QGridLayout* pGrid = new QGridLayout(pGroup);
pGrid->setContentsMargins(8, 15, 8, 10);
pGrid->setHorizontalSpacing(6);
pGrid->setVerticalSpacing(6);
// 沿用储层参数常规字段的三列规则:标签按内容,输入框与单位下拉框按 8:5 伸展。
pGrid->setColumnStretch(0, 0);
pGrid->setColumnStretch(1, 8);
pGrid->setColumnStretch(2, 5);
QLabel* pLengthLabel = new QLabel(tr("Length"), pGroup);
pLengthLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
pLengthLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
pGrid->addWidget(pLengthLabel, 0, 0);
// 长度只能由测量和端点拟合产生;只读而非禁用,允许用户选中、复制结果。
m_pLengthEdit = new QLineEdit(pGroup);
m_pLengthEdit->setObjectName("measureLength");
m_pLengthEdit->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
m_pLengthEdit->setReadOnly(true);
// 纵向 Fixed 使用当前字体和主题的推荐高度,不设置固定像素高度。
m_pLengthEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
pGrid->addWidget(m_pLengthEdit, 0, 1);
QComboBox* pLengthUnit = new QComboBox(pGroup);
pLengthUnit->setObjectName("measureLengthUnit");
// 推荐及最小宽度按完整单位列表和主题箭头计算,窗口拉宽时与输入框一起伸展。
pLengthUnit->setSizeAdjustPolicy(QComboBox::AdjustToContents);
pLengthUnit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
pGrid->addWidget(pLengthUnit, 0, 2);
// 由米识别框架长度单位组,不借用井参数及其范围,也不读取模型的旧手写单位列表。
// 单位切换和显示精度交给绑定器处理,不将显示单位或显示数值写回测量模型。
pLengthUnit->addItem("m");
m_bUnitBound = bindUnitPairWxs(m_pLengthEdit, pLengthUnit, QString(), false);
m_bUnitBound = m_bUnitBound && m_pUnitBinder != nullptr;
m_pLengthEdit->setEnabled(m_bUnitBound);
pLengthUnit->setEnabled(m_bUnitBound);
m_pFitStartButton = new QPushButton(tr("Fit start to nearest well"), pGroup);
m_pFitEndButton = new QPushButton(tr("Fit end to nearest well"), pGroup);
// 拟合属于显式操作,不设为默认按钮,避免复制长度时按回车触发端点变化。
m_pFitStartButton->setAutoDefault(false);
m_pFitEndButton->setAutoDefault(false);
m_pFitStartButton->setEnabled(false);
m_pFitEndButton->setEnabled(false);
m_pFitStartButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
m_pFitEndButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
// 两个端点操作各占一行,横跨字段区,沿用分组的统一行间距。
pGrid->addWidget(m_pFitStartButton, 1, 0, 1, 3);
pGrid->addWidget(m_pFitEndButton, 2, 0, 1, 3);
connect(m_pFitStartButton, SIGNAL(clicked()), this, SLOT(onFitStartClicked()));
connect(m_pFitEndButton, SIGNAL(clicked()), this, SLOT(onFitEndClicked()));
pMainLayout->addWidget(pGroup);
// 纵向余量由分组与底部按钮之间的布局空间吸收,内容保持紧凑排列。
pMainLayout->addStretch(1);
// 底部沿用标准按钮框、框架图标及统一留白。
QWidget* pFooter = new QWidget(this);
pFooter->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
QHBoxLayout* pFooterLayout = new QHBoxLayout(pFooter);
pFooterLayout->setContentsMargins(4, 5, 4, 5);
pFooterLayout->setSpacing(8);
pFooterLayout->addStretch();
QDialogButtonBox* pButtons = new QDialogButtonBox(
QDialogButtonBox::Close, Qt::Horizontal, pFooter);
QPushButton* pClose = pButtons->button(QDialogButtonBox::Close);
pClose->setText(tr("Close"));
pClose->setIcon(zxLoadIcon("Cancel"));
pClose->setAutoDefault(false);
pFooterLayout->addWidget(pButtons);
pMainLayout->addWidget(pFooter);
connect(pButtons, SIGNAL(rejected()), this, SLOT(onCloseClicked()));
}
void nmWxMeasureDlg::onFitStartClicked()
{
fitToNearestWell(true);
}
void nmWxMeasureDlg::onFitEndClicked()
{
fitToNearestWell(false);
}
void nmWxMeasureDlg::fitToNearestWell(bool bFitStart)
{
if (m_pDataManager.isNull() || m_pData.isNull())
{
return;
}
// 每次读取所属分析的最新井列表;无井时保留测量点和按钮状态。
const QVector<nmDataWellBase*> vecWells = m_pDataManager->getWellDataList();
const QPointF current = m_pData->getCurrentPoint();
// 沿用测量模型约定:(0, 0) 表示没有待处理的单点,按已有线段端点拟合。
const bool bSinglePoint = !(qFuzzyCompare(current.x(), 0.0) &&
qFuzzyCompare(current.y(), 0.0));
const QPointF reference = bSinglePoint ? current :
(bFitStart ? m_pData->getStartPoint() : m_pData->getEndPoint());
double dMinDistance = std::numeric_limits<double>::max();
QPointF nearest;
bool bFound = false;
for (int nIndex = 0; nIndex < vecWells.size(); ++nIndex)
{
nmDataWellBase* pWell = vecWells[nIndex];
if (pWell == nullptr)
{
continue;
}
const QPointF wellPoint(pWell->getX().getValue().toDouble(),
pWell->getY().getValue().toDouble());
const double dDistance = QLineF(reference, wellPoint).length();
if (dDistance < dMinDistance)
{
dMinDistance = dDistance;
nearest = wellPoint;
bFound = true;
}
}
if (!bFound)
{
return;
}
// 单点测量中,未拟合的一端保留点击位置;普通线段只移动指定端点。
if (bFitStart)
{
m_pFitStartButton->setEnabled(false);
m_pData->setStartPoint(nearest);
if (bSinglePoint)
{
m_pData->setEndPoint(current);
}
}
else
{
m_pFitEndButton->setEnabled(false);
if (bSinglePoint)
{
m_pData->setStartPoint(current);
}
m_pData->setEndPoint(nearest);
}
// 几何计算使用模型中的米制坐标,不读取可能已切为英尺等单位的界面文本。
const double dLength = QLineF(m_pData->getStartPoint(), m_pData->getEndPoint()).length();
nmDataAttribute length = m_pData->getLength();
length.setValue(dLength);
m_pData->setLength(length);
m_pData->setCurrentPoint(QPointF(0, 0));
updateDisplay();
}
void nmWxMeasureDlg::updateDisplay()
{
if (m_pData.isNull())
{
m_pLengthEdit->clear();
m_pFitStartButton->setEnabled(false);
m_pFitEndButton->setEnabled(false);
return;
}
if (m_bUnitBound)
{
// 更新基准值而不重建单位列表,连续测量和拟合后仍保留当前显示单位。
m_pUnitBinder->setBaseValue(m_pLengthEdit, m_pData->getLength().getValue().toDouble());
}
else
{
m_pLengthEdit->clear();
}
}
void nmWxMeasureDlg::closeEvent(QCloseEvent* event)
{
emit needDeleteMeasureObj();
iDlgBase::closeEvent(event);
}
void nmWxMeasureDlg::onCloseClicked()
{
emit needDeleteMeasureObj();
accept();
}
void nmWxMeasureDlg::resetButtons()
{
const bool bCanFit = !m_pDataManager.isNull() && !m_pData.isNull();
m_pFitStartButton->setEnabled(bCanFit);
m_pFitEndButton->setEnabled(bCanFit);
}