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

This file contains ambiguous Unicode characters!

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

#include "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);
}