|
|
|
|
|
#include "nmReservoirPropertiesSession.h"
|
|
|
|
|
|
|
|
|
|
|
|
#include "nmAttrRegistry.h"
|
|
|
|
|
|
#include "nmDataAttribute.h"
|
|
|
|
|
|
|
|
|
|
|
|
namespace
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
/** @brief 比较两个QVariant数值,保留字符串和整数的精确语义。 */
|
|
|
|
|
|
bool sameValue(const QVariant& oLeft, const QVariant& oRight)
|
|
|
|
|
|
{
|
|
|
|
|
|
return oLeft == oRight;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** @brief 比较两口井的网格相关参数。 */
|
|
|
|
|
|
bool sameWellGeometry(nmDataWellBase& oLeft, nmDataWellBase& oRight)
|
|
|
|
|
|
{
|
|
|
|
|
|
return sameValue(oLeft.getX().getValue(), oRight.getX().getValue()) &&
|
|
|
|
|
|
sameValue(oLeft.getY().getValue(), oRight.getY().getValue()) &&
|
|
|
|
|
|
sameValue(oLeft.getRadius().getValue(), oRight.getRadius().getValue());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nmReservoirPropertiesSession::nmReservoirPropertiesSession(
|
|
|
|
|
|
nmIReservoirPropertiesDataSource* pDataSource)
|
|
|
|
|
|
: m_pDataSource(pDataSource),
|
|
|
|
|
|
m_pAttrRegistry(new nmAttrRegistry),
|
|
|
|
|
|
m_bInitialized(false)
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nmReservoirPropertiesSession::~nmReservoirPropertiesSession()
|
|
|
|
|
|
{
|
|
|
|
|
|
delete m_pAttrRegistry;
|
|
|
|
|
|
m_pAttrRegistry = nullptr;
|
|
|
|
|
|
m_pDataSource = nullptr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool nmReservoirPropertiesSession::initialize(QString& sError)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 第一步:读取一次真实数据,作为取消和变更检测的基线。
|
|
|
|
|
|
if (m_pDataSource == nullptr ||
|
|
|
|
|
|
!m_pDataSource->loadSnapshot(m_oOriginalSnapshot, sError))
|
|
|
|
|
|
{
|
|
|
|
|
|
m_bInitialized = false;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 第二步:复制出独立工作副本,后续界面修改只写入此对象。
|
|
|
|
|
|
m_oWorkingSnapshot = m_oOriginalSnapshot;
|
|
|
|
|
|
nmReservoirParameterCatalog::registerSnapshot(m_pAttrRegistry,
|
|
|
|
|
|
m_oWorkingSnapshot);
|
|
|
|
|
|
m_bInitialized = true;
|
|
|
|
|
|
sError.clear();
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QList<nmReservoirPropertyObjectInfo> nmReservoirPropertiesSession::objectInfos(
|
|
|
|
|
|
nmReservoirPropertiesCategory eCategory)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!m_bInitialized)
|
|
|
|
|
|
{
|
|
|
|
|
|
return QList<nmReservoirPropertyObjectInfo>();
|
|
|
|
|
|
}
|
|
|
|
|
|
return nmReservoirParameterCatalog::createObjectInfos(eCategory,
|
|
|
|
|
|
m_oWorkingSnapshot);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QVariant nmReservoirPropertiesSession::value(const QString& sParameterId) const
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!m_bInitialized || m_pAttrRegistry == nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
return QVariant();
|
|
|
|
|
|
}
|
|
|
|
|
|
QStringList listIds;
|
|
|
|
|
|
listIds << sParameterId;
|
|
|
|
|
|
return m_pAttrRegistry->collect(listIds).value(sParameterId, QVariant());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool nmReservoirPropertiesSession::setValue(const QString& sParameterId,
|
|
|
|
|
|
const QVariant& oValue)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!m_bInitialized || m_pAttrRegistry == nullptr ||
|
|
|
|
|
|
!m_pAttrRegistry->registeredNames().contains(sParameterId))
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
m_pAttrRegistry->setValue(sParameterId, oValue);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void nmReservoirPropertiesSession::setValues(
|
|
|
|
|
|
const QMap<QString, QVariant>& mapValues)
|
|
|
|
|
|
{
|
|
|
|
|
|
QMap<QString, QVariant>::const_iterator oIterator = mapValues.constBegin();
|
|
|
|
|
|
for (; oIterator != mapValues.constEnd(); ++oIterator)
|
|
|
|
|
|
{
|
|
|
|
|
|
setValue(oIterator.key(), oIterator.value());
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QString nmReservoirPropertiesSession::enumCode(const QString& sParameterId) const
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!m_bInitialized)
|
|
|
|
|
|
{
|
|
|
|
|
|
return QString();
|
|
|
|
|
|
}
|
|
|
|
|
|
return nmReservoirParameterCatalog::enumCode(m_oWorkingSnapshot,
|
|
|
|
|
|
sParameterId);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool nmReservoirPropertiesSession::setEnumCode(const QString& sParameterId,
|
|
|
|
|
|
const QString& sCode)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!m_bInitialized)
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
return nmReservoirParameterCatalog::setEnumCode(m_oWorkingSnapshot,
|
|
|
|
|
|
sParameterId,
|
|
|
|
|
|
sCode);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool nmReservoirPropertiesSession::commit(QString& sError)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!m_bInitialized || m_pDataSource == nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
sError = QObject::tr("The reservoir properties editing session is unavailable.");
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 第一步:在提交前计算几何变更,供数据源决定是否重建网格和刷新画布。
|
|
|
|
|
|
bool bGeometryChanged = isGeometryChanged();
|
|
|
|
|
|
|
|
|
|
|
|
// 第二步:将完整工作副本一次性交给数据源;失败时继续保留当前编辑内容。
|
|
|
|
|
|
if (!m_pDataSource->commitSnapshot(m_oWorkingSnapshot,
|
|
|
|
|
|
bGeometryChanged,
|
|
|
|
|
|
sError))
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 第三步:提交成功后更新基线,防止同一会话重复识别旧变更。
|
|
|
|
|
|
m_oOriginalSnapshot = m_oWorkingSnapshot;
|
|
|
|
|
|
sError.clear();
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const nmReservoirPropertiesSnapshot&
|
|
|
|
|
|
nmReservoirPropertiesSession::workingSnapshot() const
|
|
|
|
|
|
{
|
|
|
|
|
|
return m_oWorkingSnapshot;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool nmReservoirPropertiesSession::isGeometryChanged() const
|
|
|
|
|
|
{
|
|
|
|
|
|
// 第一步:对象数量变化视为几何变化,虽然当前对话框本身不提供增删操作。
|
|
|
|
|
|
if (m_oOriginalSnapshot.m_vecVerticalWells.size() !=
|
|
|
|
|
|
m_oWorkingSnapshot.m_vecVerticalWells.size() ||
|
|
|
|
|
|
m_oOriginalSnapshot.m_vecVerticalFracturedWells.size() !=
|
|
|
|
|
|
m_oWorkingSnapshot.m_vecVerticalFracturedWells.size() ||
|
|
|
|
|
|
m_oOriginalSnapshot.m_vecHorizontalFracturedWells.size() !=
|
|
|
|
|
|
m_oWorkingSnapshot.m_vecHorizontalFracturedWells.size())
|
|
|
|
|
|
{
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 第二步:比较三类井的位置和井径。
|
|
|
|
|
|
for (int nIndex = 0; nIndex < m_oWorkingSnapshot.m_vecVerticalWells.size(); ++nIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
nmDataVerticalWell& oOriginal =
|
|
|
|
|
|
const_cast<nmDataVerticalWell&>(m_oOriginalSnapshot.m_vecVerticalWells[nIndex]);
|
|
|
|
|
|
nmDataVerticalWell& oWorking =
|
|
|
|
|
|
const_cast<nmDataVerticalWell&>(m_oWorkingSnapshot.m_vecVerticalWells[nIndex]);
|
|
|
|
|
|
if (!sameWellGeometry(oOriginal, oWorking))
|
|
|
|
|
|
{
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
for (int nIndex = 0; nIndex < m_oWorkingSnapshot.m_vecVerticalFracturedWells.size(); ++nIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
nmDataVerticalFracturedWell& oOriginal = const_cast<nmDataVerticalFracturedWell&>(
|
|
|
|
|
|
m_oOriginalSnapshot.m_vecVerticalFracturedWells[nIndex]);
|
|
|
|
|
|
nmDataVerticalFracturedWell& oWorking = const_cast<nmDataVerticalFracturedWell&>(
|
|
|
|
|
|
m_oWorkingSnapshot.m_vecVerticalFracturedWells[nIndex]);
|
|
|
|
|
|
if (!sameWellGeometry(oOriginal, oWorking) ||
|
|
|
|
|
|
!sameValue(oOriginal.getFractureHalfLength().getValue(),
|
|
|
|
|
|
oWorking.getFractureHalfLength().getValue()) ||
|
|
|
|
|
|
!sameValue(oOriginal.getFractureAngle().getValue(),
|
|
|
|
|
|
oWorking.getFractureAngle().getValue()))
|
|
|
|
|
|
{
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
for (int nIndex = 0; nIndex < m_oWorkingSnapshot.m_vecHorizontalFracturedWells.size(); ++nIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
nmDataHorizontalFracturedWell& oOriginal =
|
|
|
|
|
|
const_cast<nmDataHorizontalFracturedWell&>(
|
|
|
|
|
|
m_oOriginalSnapshot.m_vecHorizontalFracturedWells[nIndex]);
|
|
|
|
|
|
nmDataHorizontalFracturedWell& oWorking =
|
|
|
|
|
|
const_cast<nmDataHorizontalFracturedWell&>(
|
|
|
|
|
|
m_oWorkingSnapshot.m_vecHorizontalFracturedWells[nIndex]);
|
|
|
|
|
|
if (!sameWellGeometry(oOriginal, oWorking) ||
|
|
|
|
|
|
!sameValue(oOriginal.getWellLength().getValue(), oWorking.getWellLength().getValue()) ||
|
|
|
|
|
|
!sameValue(oOriginal.getDrainAngle().getValue(), oWorking.getDrainAngle().getValue()) ||
|
|
|
|
|
|
!sameValue(oOriginal.getNumberOfFractures().getValue(),
|
|
|
|
|
|
oWorking.getNumberOfFractures().getValue()) ||
|
|
|
|
|
|
!sameValue(oOriginal.getFractureHalfLength().getValue(),
|
|
|
|
|
|
oWorking.getFractureHalfLength().getValue()) ||
|
|
|
|
|
|
!sameValue(oOriginal.getFractureAngle().getValue(),
|
|
|
|
|
|
oWorking.getFractureAngle().getValue()))
|
|
|
|
|
|
{
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 第三步:断层和裂缝端点也直接参与网格,因此比较完整点坐标。
|
|
|
|
|
|
if (m_oOriginalSnapshot.m_vecFaults.size() != m_oWorkingSnapshot.m_vecFaults.size() ||
|
|
|
|
|
|
m_oOriginalSnapshot.m_vecFractures.size() != m_oWorkingSnapshot.m_vecFractures.size())
|
|
|
|
|
|
{
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
for (int nIndex = 0; nIndex < m_oWorkingSnapshot.m_vecFaults.size(); ++nIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (m_oOriginalSnapshot.m_vecFaults[nIndex].getFaultPoints() !=
|
|
|
|
|
|
m_oWorkingSnapshot.m_vecFaults[nIndex].getFaultPoints())
|
|
|
|
|
|
{
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
for (int nIndex = 0; nIndex < m_oWorkingSnapshot.m_vecFractures.size(); ++nIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (m_oOriginalSnapshot.m_vecFractures[nIndex].getFracturePoints() !=
|
|
|
|
|
|
m_oWorkingSnapshot.m_vecFractures[nIndex].getFracturePoints())
|
|
|
|
|
|
{
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|