mirror of
https://github.com/OPM/ResInsight.git
synced 2026-08-27 05:37:21 -05:00
#13316 Custom MSW well segment definitions
This commit is contained in:
@@ -16,6 +16,8 @@ set(SOURCE_GROUP_HEADER_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicImportValveTemplatesFeature.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicNewDiameterRoughnessIntervalFeature.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicDeleteDiameterRoughnessIntervalFeature.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicNewCustomSegmentIntervalFeature.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicDeleteCustomSegmentIntervalFeature.h
|
||||
)
|
||||
|
||||
set(SOURCE_GROUP_SOURCE_FILES
|
||||
@@ -36,6 +38,8 @@ set(SOURCE_GROUP_SOURCE_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicImportValveTemplatesFeature.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicNewDiameterRoughnessIntervalFeature.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicDeleteDiameterRoughnessIntervalFeature.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicNewCustomSegmentIntervalFeature.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicDeleteCustomSegmentIntervalFeature.cpp
|
||||
)
|
||||
|
||||
list(APPEND COMMAND_CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})
|
||||
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2025 Equinor ASA
|
||||
//
|
||||
// ResInsight is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
#include "RicDeleteCustomSegmentIntervalFeature.h"
|
||||
|
||||
#include "RimCustomSegmentInterval.h"
|
||||
#include "RimCustomSegmentIntervalCollection.h"
|
||||
#include "RimMswCompletionParameters.h"
|
||||
#include "RimProject.h"
|
||||
#include "RimWellPath.h"
|
||||
#include "RimWellPathCompletionSettings.h"
|
||||
|
||||
#include "Riu3DMainWindowTools.h"
|
||||
|
||||
#include "cafSelectionManager.h"
|
||||
|
||||
#include <QAction>
|
||||
|
||||
CAF_CMD_SOURCE_INIT( RicDeleteCustomSegmentIntervalFeature, "RicDeleteCustomSegmentIntervalFeature" );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RicDeleteCustomSegmentIntervalFeature::isCommandEnabled() const
|
||||
{
|
||||
if ( caf::SelectionManager::instance()->selectedItemOfType<RimCustomSegmentInterval>( caf::SelectionManager::FIRST_LEVEL ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( auto collection = caf::SelectionManager::instance()->selectedItemOfType<RimCustomSegmentIntervalCollection>() )
|
||||
{
|
||||
return collection && !collection->intervals().empty();
|
||||
}
|
||||
|
||||
if ( auto mswParams = caf::SelectionManager::instance()->selectedItemOfType<RimMswCompletionParameters>() )
|
||||
{
|
||||
if ( mswParams->customSegmentIntervals() )
|
||||
{
|
||||
return !mswParams->customSegmentIntervals()->intervals().empty();
|
||||
}
|
||||
}
|
||||
|
||||
if ( auto completionSettings = caf::SelectionManager::instance()->selectedItemOfType<RimWellPathCompletionSettings>() )
|
||||
{
|
||||
if ( auto wellPath = completionSettings->firstAncestorOrThisOfType<RimWellPath>() )
|
||||
{
|
||||
auto mswParams = wellPath->mswCompletionParameters();
|
||||
if ( mswParams && mswParams->customSegmentIntervals() )
|
||||
{
|
||||
return !mswParams->customSegmentIntervals()->intervals().empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicDeleteCustomSegmentIntervalFeature::onActionTriggered( bool isChecked )
|
||||
{
|
||||
const auto intervals = caf::SelectionManager::instance()->objectsByType<RimCustomSegmentInterval>( caf::SelectionManager::FIRST_LEVEL );
|
||||
RimCustomSegmentIntervalCollection* intervalCollection = nullptr;
|
||||
|
||||
if ( !intervals.empty() )
|
||||
{
|
||||
// Delete selected intervals
|
||||
intervalCollection = intervals[0]->firstAncestorOrThisOfTypeAsserted<RimCustomSegmentIntervalCollection>();
|
||||
for ( RimCustomSegmentInterval* intervalToDelete : intervals )
|
||||
{
|
||||
intervalCollection->removeInterval( intervalToDelete );
|
||||
}
|
||||
intervalCollection->updateConnectedEditors();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Delete all intervals in collection
|
||||
intervalCollection = caf::SelectionManager::instance()->selectedItemOfType<RimCustomSegmentIntervalCollection>();
|
||||
if ( !intervalCollection )
|
||||
{
|
||||
// Handle selection of MSW completion parameters
|
||||
auto mswParams = caf::SelectionManager::instance()->selectedItemOfType<RimMswCompletionParameters>();
|
||||
if ( mswParams && mswParams->customSegmentIntervals() )
|
||||
{
|
||||
intervalCollection = mswParams->customSegmentIntervals();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Handle selection of well path completion settings
|
||||
if ( auto completionSettings = caf::SelectionManager::instance()->selectedItemOfType<RimWellPathCompletionSettings>() )
|
||||
{
|
||||
if ( auto wellPath = completionSettings->firstAncestorOrThisOfType<RimWellPath>() )
|
||||
{
|
||||
auto mswParams = wellPath->mswCompletionParameters();
|
||||
if ( mswParams && mswParams->customSegmentIntervals() )
|
||||
{
|
||||
intervalCollection = mswParams->customSegmentIntervals();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( intervalCollection )
|
||||
{
|
||||
intervalCollection->removeAllIntervals();
|
||||
intervalCollection->updateConnectedEditors();
|
||||
}
|
||||
}
|
||||
|
||||
if ( intervalCollection )
|
||||
{
|
||||
if ( intervalCollection->intervals().empty() )
|
||||
{
|
||||
Riu3DMainWindowTools::selectAsCurrentItem( intervalCollection );
|
||||
}
|
||||
|
||||
if ( RimProject* proj = RimProject::current() )
|
||||
{
|
||||
proj->scheduleCreateDisplayModelAndRedrawAllViews();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicDeleteCustomSegmentIntervalFeature::setupActionLook( QAction* actionToSetup )
|
||||
{
|
||||
const auto intervals = caf::SelectionManager::instance()->objectsByType<RimCustomSegmentInterval>( caf::SelectionManager::FIRST_LEVEL );
|
||||
if ( !intervals.empty() )
|
||||
{
|
||||
if ( intervals.size() == 1 )
|
||||
{
|
||||
actionToSetup->setText( "Delete Segment Interval" );
|
||||
}
|
||||
else
|
||||
{
|
||||
actionToSetup->setText( QString( "Delete %1 Segment Intervals" ).arg( intervals.size() ) );
|
||||
}
|
||||
actionToSetup->setIcon( QIcon( ":/Erase.svg" ) );
|
||||
applyShortcutWithHintToAction( actionToSetup, QKeySequence::Delete );
|
||||
}
|
||||
else if ( caf::SelectionManager::instance()->selectedItemOfType<RimCustomSegmentIntervalCollection>() ||
|
||||
caf::SelectionManager::instance()->selectedItemOfType<RimMswCompletionParameters>() ||
|
||||
caf::SelectionManager::instance()->selectedItemOfType<RimWellPathCompletionSettings>() )
|
||||
{
|
||||
actionToSetup->setText( "Delete All Segment Intervals" );
|
||||
actionToSetup->setIcon( QIcon( ":/Erase.svg" ) );
|
||||
applyShortcutWithHintToAction( actionToSetup, QKeySequence::Delete );
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2025 Equinor ASA
|
||||
//
|
||||
// ResInsight is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cafCmdFeature.h"
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
class RicDeleteCustomSegmentIntervalFeature : public caf::CmdFeature
|
||||
{
|
||||
CAF_CMD_HEADER_INIT;
|
||||
|
||||
protected:
|
||||
bool isCommandEnabled() const override;
|
||||
void onActionTriggered( bool isChecked ) override;
|
||||
void setupActionLook( QAction* actionToSetup ) override;
|
||||
};
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2025 Equinor ASA
|
||||
//
|
||||
// ResInsight is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
#include "RicNewCustomSegmentIntervalFeature.h"
|
||||
|
||||
#include "RimCustomSegmentInterval.h"
|
||||
#include "RimCustomSegmentIntervalCollection.h"
|
||||
#include "RimMswCompletionParameters.h"
|
||||
#include "RimProject.h"
|
||||
#include "RimWellPath.h"
|
||||
#include "RimWellPathCompletionSettings.h"
|
||||
|
||||
#include "Riu3DMainWindowTools.h"
|
||||
|
||||
#include "cafSelectionManager.h"
|
||||
|
||||
#include <QAction>
|
||||
|
||||
CAF_CMD_SOURCE_INIT( RicNewCustomSegmentIntervalFeature, "RicNewCustomSegmentIntervalFeature" );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RicNewCustomSegmentIntervalFeature::isCommandEnabled() const
|
||||
{
|
||||
return ( caf::SelectionManager::instance()->selectedItemOfType<RimCustomSegmentIntervalCollection>() ||
|
||||
caf::SelectionManager::instance()->selectedItemOfType<RimMswCompletionParameters>() ||
|
||||
caf::SelectionManager::instance()->selectedItemOfType<RimWellPathCompletionSettings>() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicNewCustomSegmentIntervalFeature::onActionTriggered( bool isChecked )
|
||||
{
|
||||
// Try to get collection directly
|
||||
RimCustomSegmentIntervalCollection* intervalCollection =
|
||||
caf::SelectionManager::instance()->selectedItemOfType<RimCustomSegmentIntervalCollection>();
|
||||
|
||||
// If not found, try to get it from MSW completion parameters
|
||||
if ( !intervalCollection )
|
||||
{
|
||||
if ( auto mswParams = caf::SelectionManager::instance()->selectedItemOfType<RimMswCompletionParameters>() )
|
||||
{
|
||||
intervalCollection = mswParams->customSegmentIntervals();
|
||||
}
|
||||
}
|
||||
|
||||
// If still not found, try to get it from well path completion settings
|
||||
if ( !intervalCollection )
|
||||
{
|
||||
if ( auto completionSettings = caf::SelectionManager::instance()->selectedItemOfType<RimWellPathCompletionSettings>() )
|
||||
{
|
||||
if ( auto wellPath = completionSettings->firstAncestorOrThisOfType<RimWellPath>() )
|
||||
{
|
||||
if ( auto mswParams = wellPath->mswCompletionParameters() )
|
||||
{
|
||||
intervalCollection = mswParams->customSegmentIntervals();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( intervalCollection )
|
||||
{
|
||||
RimCustomSegmentInterval* newInterval = new RimCustomSegmentInterval;
|
||||
|
||||
// Set default MD values
|
||||
newInterval->setStartMD( 0 );
|
||||
newInterval->setEndMD( 100 );
|
||||
|
||||
intervalCollection->addInterval( newInterval );
|
||||
intervalCollection->updateConnectedEditors();
|
||||
|
||||
Riu3DMainWindowTools::selectAsCurrentItem( newInterval );
|
||||
|
||||
if ( RimProject* project = RimProject::current() )
|
||||
{
|
||||
project->scheduleCreateDisplayModelAndRedrawAllViews();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicNewCustomSegmentIntervalFeature::setupActionLook( QAction* actionToSetup )
|
||||
{
|
||||
actionToSetup->setText( "New Segment Interval" );
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2025 Equinor ASA
|
||||
//
|
||||
// ResInsight is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cafCmdFeature.h"
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
class RicNewCustomSegmentIntervalFeature : public caf::CmdFeature
|
||||
{
|
||||
CAF_CMD_HEADER_INIT;
|
||||
|
||||
protected:
|
||||
bool isCommandEnabled() const override;
|
||||
void onActionTriggered( bool isChecked ) override;
|
||||
void setupActionLook( QAction* actionToSetup ) override;
|
||||
};
|
||||
@@ -38,10 +38,11 @@
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicMswTableDataTools::collectWelsegsData( RigMswTableData& tableData,
|
||||
RicMswExportInfo& exportInfo,
|
||||
double maxSegmentLength,
|
||||
bool exportCompletionSegmentsAfterMainBore )
|
||||
void RicMswTableDataTools::collectWelsegsData( RigMswTableData& tableData,
|
||||
RicMswExportInfo& exportInfo,
|
||||
double maxSegmentLength,
|
||||
const std::vector<std::pair<double, double>>& customSegmentIntervals,
|
||||
bool exportCompletionSegmentsAfterMainBore )
|
||||
{
|
||||
// Set up WELSEGS header
|
||||
WelsegsHeader header;
|
||||
@@ -66,6 +67,7 @@ void RicMswTableDataTools::collectWelsegsData( RigMswTableData& tableData,
|
||||
exportInfo.mainBoreBranch(),
|
||||
&segmentNumber,
|
||||
maxSegmentLength,
|
||||
customSegmentIntervals,
|
||||
exportCompletionSegmentsAfterMainBore,
|
||||
nullptr );
|
||||
}
|
||||
@@ -73,13 +75,14 @@ void RicMswTableDataTools::collectWelsegsData( RigMswTableData& tableData,
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicMswTableDataTools::collectWelsegsDataRecursively( RigMswTableData& tableData,
|
||||
RicMswExportInfo& exportInfo,
|
||||
gsl::not_null<RicMswBranch*> branch,
|
||||
gsl::not_null<int*> segmentNumber,
|
||||
double maxSegmentLength,
|
||||
bool exportCompletionSegmentsAfterMainBore,
|
||||
RicMswSegment* connectedToSegment )
|
||||
void RicMswTableDataTools::collectWelsegsDataRecursively( RigMswTableData& tableData,
|
||||
RicMswExportInfo& exportInfo,
|
||||
gsl::not_null<RicMswBranch*> branch,
|
||||
gsl::not_null<int*> segmentNumber,
|
||||
double maxSegmentLength,
|
||||
const std::vector<std::pair<double, double>>& customSegmentIntervals,
|
||||
bool exportCompletionSegmentsAfterMainBore,
|
||||
RicMswSegment* connectedToSegment )
|
||||
{
|
||||
auto outletSegment = connectedToSegment;
|
||||
RicMswValve* outletValve = nullptr;
|
||||
@@ -90,7 +93,7 @@ void RicMswTableDataTools::collectWelsegsDataRecursively( RigMswTableData&
|
||||
// Handle tie-in ICV at the beginning of branch
|
||||
if ( outletValve = dynamic_cast<RicMswTieInICV*>( branch.get() ); outletValve != nullptr )
|
||||
{
|
||||
collectValveWelsegsSegment( tableData, outletSegment, outletValve, exportInfo, maxSegmentLength, segmentNumber );
|
||||
collectValveWelsegsSegment( tableData, outletSegment, outletValve, exportInfo, maxSegmentLength, customSegmentIntervals, segmentNumber );
|
||||
|
||||
auto valveSegments = outletValve->segments();
|
||||
outletSegment = valveSegments.front();
|
||||
@@ -111,12 +114,19 @@ void RicMswTableDataTools::collectWelsegsDataRecursively( RigMswTableData&
|
||||
branchDescription = QString( "Segments on branch %1" ).arg( branch->label() );
|
||||
}
|
||||
|
||||
collectWelsegsSegment( tableData, segment, outletSegment, exportInfo, maxSegmentLength, branch, segmentNumber, branchDescription );
|
||||
collectWelsegsSegment( tableData, segment, outletSegment, exportInfo, maxSegmentLength, customSegmentIntervals, branch, segmentNumber, branchDescription );
|
||||
outletSegment = segment;
|
||||
|
||||
if ( !exportCompletionSegmentsAfterMainBore )
|
||||
{
|
||||
collectCompletionsForSegment( tableData, outletSegment, segment, &outletValve, exportInfo, maxSegmentLength, segmentNumber );
|
||||
collectCompletionsForSegment( tableData,
|
||||
outletSegment,
|
||||
segment,
|
||||
&outletValve,
|
||||
exportInfo,
|
||||
maxSegmentLength,
|
||||
customSegmentIntervals,
|
||||
segmentNumber );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,7 +137,14 @@ void RicMswTableDataTools::collectWelsegsDataRecursively( RigMswTableData&
|
||||
for ( ; it != branchSegments.end(); ++it )
|
||||
{
|
||||
auto segment = *it;
|
||||
collectCompletionsForSegment( tableData, outletSegment, segment, &outletValve, exportInfo, maxSegmentLength, segmentNumber );
|
||||
collectCompletionsForSegment( tableData,
|
||||
outletSegment,
|
||||
segment,
|
||||
&outletValve,
|
||||
exportInfo,
|
||||
maxSegmentLength,
|
||||
customSegmentIntervals,
|
||||
segmentNumber );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,6 +160,7 @@ void RicMswTableDataTools::collectWelsegsDataRecursively( RigMswTableData&
|
||||
childBranch,
|
||||
segmentNumber,
|
||||
maxSegmentLength,
|
||||
customSegmentIntervals,
|
||||
exportCompletionSegmentsAfterMainBore,
|
||||
outletSegmentForChildBranch );
|
||||
}
|
||||
@@ -151,21 +169,23 @@ void RicMswTableDataTools::collectWelsegsDataRecursively( RigMswTableData&
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Helper function to collect WELSEGS data for a single segment with sub-segmentation
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicMswTableDataTools::collectWelsegsSegment( RigMswTableData& tableData,
|
||||
RicMswSegment* segment,
|
||||
const RicMswSegment* previousSegment,
|
||||
RicMswExportInfo& exportInfo,
|
||||
double maxSegmentLength,
|
||||
gsl::not_null<RicMswBranch*> branch,
|
||||
int* segmentNumber,
|
||||
QString branchDescription )
|
||||
void RicMswTableDataTools::collectWelsegsSegment( RigMswTableData& tableData,
|
||||
RicMswSegment* segment,
|
||||
const RicMswSegment* previousSegment,
|
||||
RicMswExportInfo& exportInfo,
|
||||
double maxSegmentLength,
|
||||
const std::vector<std::pair<double, double>>& customSegmentIntervals,
|
||||
gsl::not_null<RicMswBranch*> branch,
|
||||
int* segmentNumber,
|
||||
QString branchDescription )
|
||||
{
|
||||
CVF_ASSERT( segment && segmentNumber );
|
||||
|
||||
double startMD = segment->startMD();
|
||||
double endMD = segment->endMD();
|
||||
|
||||
std::vector<std::pair<double, double>> segments = RicMswTableFormatterTools::createSubSegmentMDPairs( startMD, endMD, maxSegmentLength );
|
||||
std::vector<std::pair<double, double>> segments =
|
||||
RicMswTableFormatterTools::createSubSegmentMDPairs( startMD, endMD, maxSegmentLength, customSegmentIntervals );
|
||||
|
||||
CVF_ASSERT( branch->wellPath() );
|
||||
|
||||
@@ -252,12 +272,13 @@ void RicMswTableDataTools::collectWelsegsSegment( RigMswTableData& t
|
||||
/// Helper function to collect WELSEGS data for valve completions
|
||||
/// Ported from RicMswTableFormatterTools::writeValveWelsegsSegment()
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicMswTableDataTools::collectValveWelsegsSegment( RigMswTableData& tableData,
|
||||
const RicMswSegment* outletSegment,
|
||||
RicMswValve* valve,
|
||||
RicMswExportInfo& exportInfo,
|
||||
double maxSegmentLength,
|
||||
int* segmentNumber )
|
||||
void RicMswTableDataTools::collectValveWelsegsSegment( RigMswTableData& tableData,
|
||||
const RicMswSegment* outletSegment,
|
||||
RicMswValve* valve,
|
||||
RicMswExportInfo& exportInfo,
|
||||
double maxSegmentLength,
|
||||
const std::vector<std::pair<double, double>>& customSegmentIntervals,
|
||||
int* segmentNumber )
|
||||
{
|
||||
if ( !valve ) return;
|
||||
if ( !valve->isValid() ) return;
|
||||
@@ -290,7 +311,7 @@ void RicMswTableDataTools::collectValveWelsegsSegment( RigMswTableData& tabl
|
||||
endMD = subSegment->endMD();
|
||||
}
|
||||
|
||||
auto splitSegments = RicMswTableFormatterTools::createSubSegmentMDPairs( startMD, endMD, maxSegmentLength );
|
||||
auto splitSegments = RicMswTableFormatterTools::createSubSegmentMDPairs( startMD, endMD, maxSegmentLength, customSegmentIntervals );
|
||||
|
||||
int outletSegmentNumber = outletSegment ? outletSegment->segmentNumber() : 1;
|
||||
const auto linerDiameter = valve->wellPath()->mswCompletionParameters()->linerDiameter( exportInfo.unitSystem() );
|
||||
@@ -344,13 +365,14 @@ void RicMswTableDataTools::collectValveWelsegsSegment( RigMswTableData& tabl
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Helper function to collect WELSEGS data for completions on a segment
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicMswTableDataTools::collectCompletionsForSegment( RigMswTableData& tableData,
|
||||
gsl::not_null<const RicMswSegment*> outletSegment,
|
||||
gsl::not_null<RicMswSegment*> segment,
|
||||
RicMswValve** outletValve,
|
||||
RicMswExportInfo& exportInfo,
|
||||
double maxSegmentLength,
|
||||
int* segmentNumber )
|
||||
void RicMswTableDataTools::collectCompletionsForSegment( RigMswTableData& tableData,
|
||||
gsl::not_null<const RicMswSegment*> outletSegment,
|
||||
gsl::not_null<RicMswSegment*> segment,
|
||||
RicMswValve** outletValve,
|
||||
RicMswExportInfo& exportInfo,
|
||||
double maxSegmentLength,
|
||||
const std::vector<std::pair<double, double>>& customSegmentIntervals,
|
||||
int* segmentNumber )
|
||||
{
|
||||
for ( auto& completion : segment->completions() )
|
||||
{
|
||||
@@ -363,7 +385,7 @@ void RicMswTableDataTools::collectCompletionsForSegment( RigMswTableData&
|
||||
auto fishboneIcd = dynamic_cast<RicMswFishbonesICD*>( completion );
|
||||
if ( !fishboneIcd && segmentValve != nullptr )
|
||||
{
|
||||
collectValveWelsegsSegment( tableData, segment, segmentValve, exportInfo, maxSegmentLength, segmentNumber );
|
||||
collectValveWelsegsSegment( tableData, segment, segmentValve, exportInfo, maxSegmentLength, customSegmentIntervals, segmentNumber );
|
||||
*outletValve = segmentValve;
|
||||
}
|
||||
else if ( dynamic_cast<RicMswTieInICV*>( completion ) )
|
||||
@@ -371,12 +393,18 @@ void RicMswTableDataTools::collectCompletionsForSegment( RigMswTableData&
|
||||
// Special handling for Tie-in ICVs
|
||||
RicMswSegment* outletSegmentForCompletion =
|
||||
*outletValve && ( *outletValve )->segmentCount() > 0 ? ( *outletValve )->segments().front() : segment.get();
|
||||
collectCompletionWelsegsSegments( tableData, outletSegmentForCompletion, completion, exportInfo, maxSegmentLength, segmentNumber );
|
||||
collectCompletionWelsegsSegments( tableData,
|
||||
outletSegmentForCompletion,
|
||||
completion,
|
||||
exportInfo,
|
||||
maxSegmentLength,
|
||||
customSegmentIntervals,
|
||||
segmentNumber );
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is the default case for completions that are not valves
|
||||
collectCompletionWelsegsSegments( tableData, segment, completion, exportInfo, maxSegmentLength, segmentNumber );
|
||||
collectCompletionWelsegsSegments( tableData, segment, completion, exportInfo, maxSegmentLength, customSegmentIntervals, segmentNumber );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -385,12 +413,13 @@ void RicMswTableDataTools::collectCompletionsForSegment( RigMswTableData&
|
||||
/// Helper function to collect WELSEGS data for a completion's segments
|
||||
/// Porting of RicMswTableFormatterTools::writeCompletionWelsegsSegments()
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicMswTableDataTools::collectCompletionWelsegsSegments( RigMswTableData& tableData,
|
||||
gsl::not_null<const RicMswSegment*> outletSegment,
|
||||
gsl::not_null<RicMswCompletion*> completion,
|
||||
RicMswExportInfo& exportInfo,
|
||||
double maxSegmentLength,
|
||||
int* segmentNumber )
|
||||
void RicMswTableDataTools::collectCompletionWelsegsSegments( RigMswTableData& tableData,
|
||||
gsl::not_null<const RicMswSegment*> outletSegment,
|
||||
gsl::not_null<RicMswCompletion*> completion,
|
||||
RicMswExportInfo& exportInfo,
|
||||
double maxSegmentLength,
|
||||
const std::vector<std::pair<double, double>>& customSegmentIntervals,
|
||||
int* segmentNumber )
|
||||
{
|
||||
bool isDescriptionAdded = false;
|
||||
|
||||
@@ -405,7 +434,7 @@ void RicMswTableDataTools::collectCompletionWelsegsSegments( RigMswTableData&
|
||||
double startTVD = segment->startTVD();
|
||||
double endTVD = segment->endTVD();
|
||||
|
||||
auto splitSegments = RicMswTableFormatterTools::createSubSegmentMDPairs( startMD, endMD, maxSegmentLength );
|
||||
auto splitSegments = RicMswTableFormatterTools::createSubSegmentMDPairs( startMD, endMD, maxSegmentLength, customSegmentIntervals );
|
||||
for ( const auto& [subStartMD, subEndMD] : splitSegments )
|
||||
{
|
||||
int subSegmentNumber = ( *segmentNumber )++;
|
||||
@@ -469,7 +498,7 @@ void RicMswTableDataTools::collectCompletionWelsegsSegments( RigMswTableData&
|
||||
|
||||
for ( auto comp : segment->completions() )
|
||||
{
|
||||
collectCompletionWelsegsSegments( tableData, segment, comp, exportInfo, maxSegmentLength, segmentNumber );
|
||||
collectCompletionWelsegsSegments( tableData, segment, comp, exportInfo, maxSegmentLength, customSegmentIntervals, segmentNumber );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,18 +74,20 @@ public:
|
||||
};
|
||||
|
||||
// New data collection functions (replace formatter versions)
|
||||
void collectWelsegsData( RigMswTableData& tableData,
|
||||
RicMswExportInfo& exportInfo,
|
||||
double maxSegmentLength,
|
||||
bool exportCompletionSegmentsAfterMainBore );
|
||||
void collectWelsegsData( RigMswTableData& tableData,
|
||||
RicMswExportInfo& exportInfo,
|
||||
double maxSegmentLength,
|
||||
const std::vector<std::pair<double, double>>& customSegmentIntervals,
|
||||
bool exportCompletionSegmentsAfterMainBore );
|
||||
|
||||
void collectWelsegsDataRecursively( RigMswTableData& tableData,
|
||||
RicMswExportInfo& exportInfo,
|
||||
gsl::not_null<RicMswBranch*> branch,
|
||||
gsl::not_null<int*> segmentNumber,
|
||||
double maxSegmentLength,
|
||||
bool exportCompletionSegmentsAfterMainBore,
|
||||
RicMswSegment* connectedToSegment );
|
||||
void collectWelsegsDataRecursively( RigMswTableData& tableData,
|
||||
RicMswExportInfo& exportInfo,
|
||||
gsl::not_null<RicMswBranch*> branch,
|
||||
gsl::not_null<int*> segmentNumber,
|
||||
double maxSegmentLength,
|
||||
const std::vector<std::pair<double, double>>& customSegmentIntervals,
|
||||
bool exportCompletionSegmentsAfterMainBore,
|
||||
RicMswSegment* connectedToSegment );
|
||||
|
||||
void collectCompsegData( RigMswTableData& tableData, RicMswExportInfo& exportInfo, bool exportSubGridIntersections );
|
||||
|
||||
@@ -105,36 +107,40 @@ void collectWsegAicdData( RigMswTableData& tableData, RicMswExportInfo& exportIn
|
||||
void collectWsegAicdDataRecursively( RigMswTableData& tableData, RicMswExportInfo& exportInfo, gsl::not_null<const RicMswBranch*> branch );
|
||||
|
||||
// Helper functions for data collection
|
||||
void collectWelsegsSegment( RigMswTableData& tableData,
|
||||
RicMswSegment* segment,
|
||||
const RicMswSegment* previousSegment,
|
||||
RicMswExportInfo& exportInfo,
|
||||
double maxSegmentLength,
|
||||
gsl::not_null<RicMswBranch*> branch,
|
||||
int* segmentNumber,
|
||||
QString branchDescription );
|
||||
void collectWelsegsSegment( RigMswTableData& tableData,
|
||||
RicMswSegment* segment,
|
||||
const RicMswSegment* previousSegment,
|
||||
RicMswExportInfo& exportInfo,
|
||||
double maxSegmentLength,
|
||||
const std::vector<std::pair<double, double>>& customSegmentIntervals,
|
||||
gsl::not_null<RicMswBranch*> branch,
|
||||
int* segmentNumber,
|
||||
QString branchDescription );
|
||||
|
||||
void collectValveWelsegsSegment( RigMswTableData& tableData,
|
||||
const RicMswSegment* outletSegment,
|
||||
RicMswValve* valve,
|
||||
RicMswExportInfo& exportInfo,
|
||||
double maxSegmentLength,
|
||||
int* segmentNumber );
|
||||
void collectValveWelsegsSegment( RigMswTableData& tableData,
|
||||
const RicMswSegment* outletSegment,
|
||||
RicMswValve* valve,
|
||||
RicMswExportInfo& exportInfo,
|
||||
double maxSegmentLength,
|
||||
const std::vector<std::pair<double, double>>& customSegmentIntervals,
|
||||
int* segmentNumber );
|
||||
|
||||
void collectCompletionsForSegment( RigMswTableData& tableData,
|
||||
gsl::not_null<const RicMswSegment*> outletSegment,
|
||||
gsl::not_null<RicMswSegment*> segment,
|
||||
RicMswValve** outletValve,
|
||||
RicMswExportInfo& exportInfo,
|
||||
double maxSegmentLength,
|
||||
int* segmentNumber );
|
||||
void collectCompletionsForSegment( RigMswTableData& tableData,
|
||||
gsl::not_null<const RicMswSegment*> outletSegment,
|
||||
gsl::not_null<RicMswSegment*> segment,
|
||||
RicMswValve** outletValve,
|
||||
RicMswExportInfo& exportInfo,
|
||||
double maxSegmentLength,
|
||||
const std::vector<std::pair<double, double>>& customSegmentIntervals,
|
||||
int* segmentNumber );
|
||||
|
||||
void collectCompletionWelsegsSegments( RigMswTableData& tableData,
|
||||
gsl::not_null<const RicMswSegment*> outletSegment,
|
||||
gsl::not_null<RicMswCompletion*> completion,
|
||||
RicMswExportInfo& exportInfo,
|
||||
double maxSegmentLength,
|
||||
int* segmentNumber );
|
||||
void collectCompletionWelsegsSegments( RigMswTableData& tableData,
|
||||
gsl::not_null<const RicMswSegment*> outletSegment,
|
||||
gsl::not_null<RicMswCompletion*> completion,
|
||||
RicMswExportInfo& exportInfo,
|
||||
double maxSegmentLength,
|
||||
const std::vector<std::pair<double, double>>& customSegmentIntervals,
|
||||
int* segmentNumber );
|
||||
|
||||
void generateWsegAicdTableRecursively( RicMswExportInfo& exportInfo,
|
||||
gsl::not_null<const RicMswBranch*> branch,
|
||||
|
||||
+97
-12
@@ -910,24 +910,109 @@ void RicMswTableFormatterTools::writeCompletionsForSegment( gsl::not_null<const
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
/// Creates sub-segment MD pairs by combining custom intervals with max segment length subdivision
|
||||
/// Custom intervals define exact segment boundaries where specified
|
||||
/// Areas without custom intervals use max segment length subdivision (if maxSegmentLength > 0)
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<std::pair<double, double>> RicMswTableFormatterTools::createSubSegmentMDPairs( double startMD, double endMD, double maxSegmentLength )
|
||||
std::vector<std::pair<double, double>>
|
||||
RicMswTableFormatterTools::createSubSegmentMDPairs( double startMD,
|
||||
double endMD,
|
||||
double maxSegmentLength,
|
||||
const std::vector<std::pair<double, double>>& customSegmentIntervals )
|
||||
{
|
||||
int subSegmentCount = (int)( std::trunc( ( endMD - startMD ) / maxSegmentLength ) + 1 );
|
||||
|
||||
double subSegmentLength = ( endMD - startMD ) / subSegmentCount;
|
||||
|
||||
std::vector<std::pair<double, double>> subSegmentMDPairs;
|
||||
|
||||
double subStartMD = startMD;
|
||||
double subEndMD = startMD + subSegmentLength;
|
||||
for ( int i = 0; i < subSegmentCount; ++i )
|
||||
// If no custom intervals, use original logic with maxSegmentLength subdivision
|
||||
if ( customSegmentIntervals.empty() || maxSegmentLength <= 0.0 )
|
||||
{
|
||||
subSegmentMDPairs.push_back( std::make_pair( subStartMD, subEndMD ) );
|
||||
subStartMD += subSegmentLength;
|
||||
subEndMD += std::min( subSegmentLength, endMD );
|
||||
int subSegmentCount = maxSegmentLength > 0.0 ? (int)( std::trunc( ( endMD - startMD ) / maxSegmentLength ) + 1 ) : 1;
|
||||
double subSegmentLength = ( endMD - startMD ) / subSegmentCount;
|
||||
|
||||
double subStartMD = startMD;
|
||||
double subEndMD = startMD + subSegmentLength;
|
||||
for ( int i = 0; i < subSegmentCount; ++i )
|
||||
{
|
||||
subSegmentMDPairs.push_back( std::make_pair( subStartMD, subEndMD ) );
|
||||
subStartMD += subSegmentLength;
|
||||
subEndMD = std::min( subEndMD + subSegmentLength, endMD );
|
||||
}
|
||||
return subSegmentMDPairs;
|
||||
}
|
||||
|
||||
// Combine custom intervals with maxSegmentLength subdivision
|
||||
// Collect all boundaries (start, end, custom interval boundaries) and sort them
|
||||
std::set<double> boundaries;
|
||||
boundaries.insert( startMD );
|
||||
boundaries.insert( endMD );
|
||||
|
||||
// Add custom interval boundaries that overlap with [startMD, endMD]
|
||||
for ( const auto& [customStart, customEnd] : customSegmentIntervals )
|
||||
{
|
||||
// Check if custom interval overlaps with [startMD, endMD]
|
||||
if ( customEnd > startMD && customStart < endMD )
|
||||
{
|
||||
// Clip custom interval to [startMD, endMD] range
|
||||
double clippedStart = std::max( customStart, startMD );
|
||||
double clippedEnd = std::min( customEnd, endMD );
|
||||
|
||||
if ( clippedStart < clippedEnd )
|
||||
{
|
||||
boundaries.insert( clippedStart );
|
||||
boundaries.insert( clippedEnd );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert boundaries to sorted vector
|
||||
std::vector<double> sortedBoundaries( boundaries.begin(), boundaries.end() );
|
||||
|
||||
// For each gap between boundaries, either:
|
||||
// - Use exact boundary if it's from a custom interval
|
||||
// - Subdivide using maxSegmentLength if it's a gap
|
||||
for ( size_t i = 0; i + 1 < sortedBoundaries.size(); ++i )
|
||||
{
|
||||
double gapStart = sortedBoundaries[i];
|
||||
double gapEnd = sortedBoundaries[i + 1];
|
||||
|
||||
// Check if this gap is covered by a custom interval
|
||||
bool coveredByCustomInterval = false;
|
||||
for ( const auto& [customStart, customEnd] : customSegmentIntervals )
|
||||
{
|
||||
double clippedStart = std::max( customStart, startMD );
|
||||
double clippedEnd = std::min( customEnd, endMD );
|
||||
|
||||
// If the gap is fully within a custom interval, use exact boundaries
|
||||
if ( gapStart >= clippedStart && gapEnd <= clippedEnd && std::abs( gapStart - clippedStart ) < 1e-6 &&
|
||||
std::abs( gapEnd - clippedEnd ) < 1e-6 )
|
||||
{
|
||||
coveredByCustomInterval = true;
|
||||
subSegmentMDPairs.push_back( std::make_pair( gapStart, gapEnd ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If not covered by custom interval, subdivide using maxSegmentLength
|
||||
if ( !coveredByCustomInterval && maxSegmentLength > 0.0 )
|
||||
{
|
||||
double gapLength = gapEnd - gapStart;
|
||||
int subCount = (int)( std::trunc( gapLength / maxSegmentLength ) + 1 );
|
||||
double subLength = gapLength / subCount;
|
||||
|
||||
double subStart = gapStart;
|
||||
for ( int j = 0; j < subCount; ++j )
|
||||
{
|
||||
double subEnd = ( j == subCount - 1 ) ? gapEnd : subStart + subLength;
|
||||
subSegmentMDPairs.push_back( std::make_pair( subStart, subEnd ) );
|
||||
subStart = subEnd;
|
||||
}
|
||||
}
|
||||
else if ( !coveredByCustomInterval )
|
||||
{
|
||||
// No maxSegmentLength, use gap as-is
|
||||
subSegmentMDPairs.push_back( std::make_pair( gapStart, gapEnd ) );
|
||||
}
|
||||
}
|
||||
|
||||
return subSegmentMDPairs;
|
||||
}
|
||||
|
||||
|
||||
@@ -122,7 +122,10 @@ void generateWsegvalvTableRecursively( gsl::not_null<RicMswBranch*>
|
||||
|
||||
void generateWsegAicdTable( RifTextDataTableFormatter& formatter, RicMswExportInfo& exportInfo );
|
||||
|
||||
std::vector<std::pair<double, double>> createSubSegmentMDPairs( double startMD, double endMD, double maxSegmentLength );
|
||||
std::vector<std::pair<double, double>> createSubSegmentMDPairs( double startMD,
|
||||
double endMD,
|
||||
double maxSegmentLength,
|
||||
const std::vector<std::pair<double, double>>& customSegmentIntervals = {} );
|
||||
|
||||
double tvdFromMeasuredDepth( gsl::not_null<const RimWellPath*> wellPath, double measuredDepth );
|
||||
|
||||
|
||||
+8
-1
@@ -119,8 +119,15 @@ std::expected<RigMswTableData, std::string> RicWellPathExportMswTableData::extra
|
||||
// Create table data container and extract data
|
||||
RigMswTableData tableData( wellPath->completionSettings()->wellNameForExport().toStdString(), unitSystem );
|
||||
|
||||
// Extract custom segment intervals from MSW parameters
|
||||
std::vector<std::pair<double, double>> customSegmentIntervals = mswParameters->getSegmentIntervals();
|
||||
|
||||
// Use the new collection functions to populate the table data
|
||||
RicMswTableDataTools::collectWelsegsData( tableData, exportInfo, mswParameters->maxSegmentLength(), exportCompletionsAfterMainBoreSegments );
|
||||
RicMswTableDataTools::collectWelsegsData( tableData,
|
||||
exportInfo,
|
||||
mswParameters->maxSegmentLength(),
|
||||
customSegmentIntervals,
|
||||
exportCompletionsAfterMainBoreSegments );
|
||||
|
||||
{
|
||||
// Get COMPSEGS for main grid
|
||||
|
||||
@@ -34,6 +34,8 @@ set(SOURCE_GROUP_HEADER_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimWellPathAicdParameters.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimDiameterRoughnessInterval.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimDiameterRoughnessIntervalCollection.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimCustomSegmentInterval.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimCustomSegmentIntervalCollection.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimEnsembleFractureStatistics.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimEnsembleFractureStatisticsCollection.h
|
||||
)
|
||||
@@ -71,6 +73,8 @@ set(SOURCE_GROUP_SOURCE_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimWellPathAicdParameters.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimDiameterRoughnessInterval.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimDiameterRoughnessIntervalCollection.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimCustomSegmentInterval.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimCustomSegmentIntervalCollection.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimEnsembleFractureStatistics.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimEnsembleFractureStatisticsCollection.cpp
|
||||
)
|
||||
|
||||
@@ -0,0 +1,240 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2025 Equinor ASA
|
||||
//
|
||||
// ResInsight is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "RimCustomSegmentInterval.h"
|
||||
|
||||
#include "RiaApplication.h"
|
||||
#include "RiaLogging.h"
|
||||
#include "RimCustomSegmentIntervalCollection.h"
|
||||
|
||||
#include "cafPdmFieldScriptingCapability.h"
|
||||
#include "cafPdmObjectScriptingCapability.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
CAF_PDM_SOURCE_INIT( RimCustomSegmentInterval, "CustomSegmentInterval" );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimCustomSegmentInterval::RimCustomSegmentInterval()
|
||||
{
|
||||
CAF_PDM_InitScriptableObject( "Custom Segment Interval", ":/WellPathComponent16x16.png", "", "CustomSegmentInterval" );
|
||||
CAF_PDM_InitScriptableField( &m_startMD, "StartMd", 0.0, "Start MD" );
|
||||
CAF_PDM_InitScriptableField( &m_endMD, "EndMd", 100.0, "End MD" );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimCustomSegmentInterval::~RimCustomSegmentInterval()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RimCustomSegmentInterval::startMD() const
|
||||
{
|
||||
return m_startMD;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RimCustomSegmentInterval::endMD() const
|
||||
{
|
||||
return m_endMD;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCustomSegmentInterval::setStartMD( double startMD )
|
||||
{
|
||||
m_startMD = startMD;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCustomSegmentInterval::setEndMD( double endMD )
|
||||
{
|
||||
m_endMD = endMD;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RimCustomSegmentInterval::isValidInterval() const
|
||||
{
|
||||
return m_endMD > m_startMD;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RimCustomSegmentInterval::overlaps( const RimCustomSegmentInterval* other ) const
|
||||
{
|
||||
if ( !other ) return false;
|
||||
|
||||
return m_endMD > other->startMD() && m_startMD < other->endMD();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RimCustomSegmentInterval::containsMD( double md ) const
|
||||
{
|
||||
return md >= m_startMD && md <= m_endMD;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RimCustomSegmentInterval::operator<( const RimCustomSegmentInterval& rhs ) const
|
||||
{
|
||||
return m_startMD < rhs.m_startMD;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RimCustomSegmentInterval::isEnabled() const
|
||||
{
|
||||
return true; // Always enabled
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaDefines::WellPathComponentType RimCustomSegmentInterval::componentType() const
|
||||
{
|
||||
return RiaDefines::WellPathComponentType::PERFORATION_INTERVAL;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RimCustomSegmentInterval::componentLabel() const
|
||||
{
|
||||
return generateDisplayLabel();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RimCustomSegmentInterval::componentTypeLabel() const
|
||||
{
|
||||
return "Custom Segment";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cvf::Color3f RimCustomSegmentInterval::defaultComponentColor() const
|
||||
{
|
||||
return cvf::Color3f( 0.2f, 0.6f, 0.8f ); // Blue color for custom segments
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCustomSegmentInterval::applyOffset( double offsetMD )
|
||||
{
|
||||
m_startMD = m_startMD + offsetMD;
|
||||
m_endMD = m_endMD + offsetMD;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCustomSegmentInterval::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
|
||||
{
|
||||
if ( changedField == &m_startMD || changedField == &m_endMD )
|
||||
{
|
||||
// Validate interval
|
||||
if ( m_startMD >= m_endMD )
|
||||
{
|
||||
RiaLogging::warning( "Invalid interval: Start MD must be less than End MD" );
|
||||
}
|
||||
|
||||
// Update overlap visual feedback in parent collection
|
||||
auto* collection = firstAncestorOrThisOfType<RimCustomSegmentIntervalCollection>();
|
||||
if ( collection )
|
||||
{
|
||||
collection->updateOverlapVisualFeedback();
|
||||
}
|
||||
}
|
||||
|
||||
updateConnectedEditors();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCustomSegmentInterval::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
|
||||
{
|
||||
uiOrdering.add( &m_startMD );
|
||||
uiOrdering.add( &m_endMD );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCustomSegmentInterval::updateConnectedEditors()
|
||||
{
|
||||
// Update any connected UI editors
|
||||
m_startMD.uiCapability()->updateConnectedEditors();
|
||||
m_endMD.uiCapability()->updateConnectedEditors();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RimCustomSegmentInterval::generateDisplayLabel() const
|
||||
{
|
||||
return QString( "MD %.1f-%.1f" ).arg( m_startMD() ).arg( m_endMD() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCustomSegmentInterval::updateOverlapVisualFeedback( bool hasOverlap )
|
||||
{
|
||||
if ( hasOverlap )
|
||||
{
|
||||
// Set red color for overlapping fields
|
||||
m_startMD.uiCapability()->setUiContentTextColor( Qt::red );
|
||||
m_endMD.uiCapability()->setUiContentTextColor( Qt::red );
|
||||
|
||||
// Create tooltip with overlap information
|
||||
QString tooltip = "This interval overlaps with another interval!";
|
||||
|
||||
m_startMD.uiCapability()->setUiToolTip( tooltip );
|
||||
m_endMD.uiCapability()->setUiToolTip( tooltip );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Reset color and tooltip
|
||||
m_startMD.uiCapability()->setUiContentTextColor( QColor() );
|
||||
m_endMD.uiCapability()->setUiContentTextColor( QColor() );
|
||||
m_startMD.uiCapability()->setUiToolTip( "" );
|
||||
m_endMD.uiCapability()->setUiToolTip( "" );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2025 Equinor ASA
|
||||
//
|
||||
// ResInsight is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma once
|
||||
|
||||
#include "RiaDefines.h"
|
||||
#include "RimWellPathComponentInterface.h"
|
||||
|
||||
#include "cafPdmField.h"
|
||||
#include "cafPdmObject.h"
|
||||
|
||||
#include <QString>
|
||||
|
||||
class RimWellPath;
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
/// Represents a custom segment interval for a specific measured depth range
|
||||
///
|
||||
//==================================================================================================
|
||||
class RimCustomSegmentInterval : public caf::PdmObject, public RimWellPathComponentInterface
|
||||
{
|
||||
CAF_PDM_HEADER_INIT;
|
||||
|
||||
public:
|
||||
RimCustomSegmentInterval();
|
||||
~RimCustomSegmentInterval() override;
|
||||
|
||||
// Getters
|
||||
double startMD() const override;
|
||||
double endMD() const override;
|
||||
|
||||
// Setters
|
||||
void setStartMD( double startMD );
|
||||
void setEndMD( double endMD );
|
||||
|
||||
// Validation
|
||||
bool isValidInterval() const;
|
||||
bool overlaps( const RimCustomSegmentInterval* other ) const;
|
||||
bool containsMD( double md ) const;
|
||||
|
||||
// Comparison for sorting
|
||||
bool operator<( const RimCustomSegmentInterval& rhs ) const;
|
||||
|
||||
// Overrides from RimWellPathComponentInterface
|
||||
bool isEnabled() const override;
|
||||
RiaDefines::WellPathComponentType componentType() const override;
|
||||
QString componentLabel() const override;
|
||||
QString componentTypeLabel() const override;
|
||||
cvf::Color3f defaultComponentColor() const override;
|
||||
void applyOffset( double offsetMD ) override;
|
||||
|
||||
// Visual feedback for overlapping intervals
|
||||
void updateOverlapVisualFeedback( bool hasOverlap );
|
||||
|
||||
protected:
|
||||
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
|
||||
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
|
||||
|
||||
private:
|
||||
void updateConnectedEditors();
|
||||
QString generateDisplayLabel() const;
|
||||
|
||||
private:
|
||||
caf::PdmField<double> m_startMD;
|
||||
caf::PdmField<double> m_endMD;
|
||||
};
|
||||
+378
@@ -0,0 +1,378 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2025 Equinor ASA
|
||||
//
|
||||
// ResInsight is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "RimCustomSegmentIntervalCollection.h"
|
||||
|
||||
#include "RiaLogging.h"
|
||||
#include "RimCustomSegmentInterval.h"
|
||||
|
||||
#include "cafCmdFeatureMenuBuilder.h"
|
||||
#include "cafPdmUiTableViewEditor.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
CAF_PDM_SOURCE_INIT( RimCustomSegmentIntervalCollection, "CustomSegmentIntervalCollection" );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimCustomSegmentIntervalCollection::RimCustomSegmentIntervalCollection()
|
||||
{
|
||||
CAF_PDM_InitObject( "Custom Segment Intervals", ":/WellPathComponent16x16.png" );
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_intervals, "Intervals", "Intervals" );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimCustomSegmentIntervalCollection::~RimCustomSegmentIntervalCollection()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<RimCustomSegmentInterval*> RimCustomSegmentIntervalCollection::intervals() const
|
||||
{
|
||||
return m_intervals.childrenByType();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCustomSegmentIntervalCollection::addInterval( RimCustomSegmentInterval* interval )
|
||||
{
|
||||
if ( interval )
|
||||
{
|
||||
m_intervals.push_back( interval );
|
||||
sortIntervalsByMD();
|
||||
updateConnectedEditors();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCustomSegmentIntervalCollection::removeInterval( RimCustomSegmentInterval* interval )
|
||||
{
|
||||
if ( interval )
|
||||
{
|
||||
m_intervals.removeChild( interval );
|
||||
delete interval;
|
||||
updateConnectedEditors();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCustomSegmentIntervalCollection::removeAllIntervals()
|
||||
{
|
||||
m_intervals.deleteChildren();
|
||||
updateConnectedEditors();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimCustomSegmentInterval* RimCustomSegmentIntervalCollection::createInterval( double startMD, double endMD )
|
||||
{
|
||||
auto* interval = new RimCustomSegmentInterval();
|
||||
interval->setStartMD( startMD );
|
||||
interval->setEndMD( endMD );
|
||||
|
||||
addInterval( interval );
|
||||
return interval;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimCustomSegmentInterval* RimCustomSegmentIntervalCollection::createDefaultInterval()
|
||||
{
|
||||
auto* interval = new RimCustomSegmentInterval();
|
||||
addInterval( interval );
|
||||
return interval;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimCustomSegmentInterval* RimCustomSegmentIntervalCollection::findIntervalAtMD( double md ) const
|
||||
{
|
||||
for ( auto* interval : intervals() )
|
||||
{
|
||||
if ( interval && interval->containsMD( md ) )
|
||||
{
|
||||
return interval;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RimCustomSegmentIntervalCollection::hasValidIntervals() const
|
||||
{
|
||||
if ( isEmpty() ) return false;
|
||||
|
||||
for ( auto* interval : intervals() )
|
||||
{
|
||||
if ( !interval || !interval->isValidInterval() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RimCustomSegmentIntervalCollection::hasOverlappingIntervals() const
|
||||
{
|
||||
auto intervalList = intervals();
|
||||
|
||||
for ( size_t i = 0; i < intervalList.size(); ++i )
|
||||
{
|
||||
for ( size_t j = i + 1; j < intervalList.size(); ++j )
|
||||
{
|
||||
if ( intervalList[i]->overlaps( intervalList[j] ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<QString> RimCustomSegmentIntervalCollection::validateIntervals() const
|
||||
{
|
||||
std::vector<QString> issues;
|
||||
|
||||
if ( isEmpty() )
|
||||
{
|
||||
issues.push_back( "No intervals defined" );
|
||||
return issues;
|
||||
}
|
||||
|
||||
auto intervalList = intervals();
|
||||
|
||||
// Check for invalid intervals
|
||||
for ( auto* interval : intervalList )
|
||||
{
|
||||
if ( !interval->isValidInterval() )
|
||||
{
|
||||
issues.push_back(
|
||||
QString( "Invalid interval: MD %.1f-%.1f (Start MD must be less than End MD)" ).arg( interval->startMD() ).arg( interval->endMD() ) );
|
||||
}
|
||||
}
|
||||
|
||||
// Check for overlaps
|
||||
for ( size_t i = 0; i < intervalList.size(); ++i )
|
||||
{
|
||||
for ( size_t j = i + 1; j < intervalList.size(); ++j )
|
||||
{
|
||||
if ( intervalList[i]->overlaps( intervalList[j] ) )
|
||||
{
|
||||
issues.push_back( QString( "Overlapping intervals: MD %.1f-%.1f and MD %.1f-%.1f" )
|
||||
.arg( intervalList[i]->startMD() )
|
||||
.arg( intervalList[i]->endMD() )
|
||||
.arg( intervalList[j]->startMD() )
|
||||
.arg( intervalList[j]->endMD() ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return issues;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCustomSegmentIntervalCollection::sortIntervalsByMD()
|
||||
{
|
||||
auto intervalList = intervals();
|
||||
std::sort( intervalList.begin(),
|
||||
intervalList.end(),
|
||||
[]( const RimCustomSegmentInterval* a, const RimCustomSegmentInterval* b ) { return *a < *b; } );
|
||||
|
||||
// Rebuild the collection in sorted order
|
||||
m_intervals.clearWithoutDelete();
|
||||
for ( auto* interval : intervalList )
|
||||
{
|
||||
m_intervals.push_back( interval );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RimCustomSegmentIntervalCollection::isEmpty() const
|
||||
{
|
||||
return m_intervals.empty();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
size_t RimCustomSegmentIntervalCollection::count() const
|
||||
{
|
||||
return m_intervals.size();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCustomSegmentIntervalCollection::updateConnectedEditors()
|
||||
{
|
||||
m_intervals.uiCapability()->updateConnectedEditors();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
caf::PdmChildArrayField<RimCustomSegmentInterval*>& RimCustomSegmentIntervalCollection::intervalsField()
|
||||
{
|
||||
return m_intervals;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCustomSegmentIntervalCollection::updateOverlapVisualFeedback()
|
||||
{
|
||||
auto intervalList = intervals();
|
||||
|
||||
// First, reset all intervals to no overlap
|
||||
for ( auto* interval : intervalList )
|
||||
{
|
||||
interval->updateOverlapVisualFeedback( false );
|
||||
}
|
||||
|
||||
// Then check for overlaps and update visual feedback
|
||||
for ( size_t i = 0; i < intervalList.size(); ++i )
|
||||
{
|
||||
bool hasOverlap = false;
|
||||
|
||||
for ( size_t j = 0; j < intervalList.size(); ++j )
|
||||
{
|
||||
if ( i != j && intervalList[i]->overlaps( intervalList[j] ) )
|
||||
{
|
||||
hasOverlap = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( hasOverlap )
|
||||
{
|
||||
intervalList[i]->updateOverlapVisualFeedback( true );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCustomSegmentIntervalCollection::fieldChangedByUi( const caf::PdmFieldHandle* changedField,
|
||||
const QVariant& oldValue,
|
||||
const QVariant& newValue )
|
||||
{
|
||||
if ( changedField == &m_intervals )
|
||||
{
|
||||
sortIntervalsByMD();
|
||||
updateOverlapVisualFeedback();
|
||||
}
|
||||
|
||||
updateConnectedEditors();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCustomSegmentIntervalCollection::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
|
||||
{
|
||||
uiOrdering.add( &m_intervals );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCustomSegmentIntervalCollection::defineEditorAttribute( const caf::PdmFieldHandle* field,
|
||||
QString uiConfigName,
|
||||
caf::PdmUiEditorAttribute* attribute )
|
||||
{
|
||||
if ( field == &m_intervals )
|
||||
{
|
||||
auto tvAttribute = dynamic_cast<caf::PdmUiTableViewEditorAttribute*>( attribute );
|
||||
if ( tvAttribute )
|
||||
{
|
||||
tvAttribute->resizePolicy = caf::PdmUiTableViewEditorAttribute::RESIZE_TO_FILL_CONTAINER;
|
||||
tvAttribute->alwaysEnforceResizePolicy = true;
|
||||
tvAttribute->minimumHeight = 300;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCustomSegmentIntervalCollection::onChildDeleted( caf::PdmChildArrayFieldHandle* childArray,
|
||||
std::vector<caf::PdmObjectHandle*>& referringObjects )
|
||||
{
|
||||
updateConnectedEditors();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCustomSegmentIntervalCollection::defineCustomContextMenu( const caf::PdmFieldHandle* fieldNeedingMenu,
|
||||
QMenu* menu,
|
||||
QWidget* fieldEditorWidget )
|
||||
{
|
||||
caf::CmdFeatureMenuBuilder menuBuilder;
|
||||
|
||||
menuBuilder << "RicNewCustomSegmentIntervalFeature";
|
||||
menuBuilder << "Separator";
|
||||
menuBuilder << "RicDeleteCustomSegmentIntervalFeature";
|
||||
|
||||
menuBuilder.appendToMenu( menu );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCustomSegmentIntervalCollection::insertInterval( RimCustomSegmentInterval* insertBefore, RimCustomSegmentInterval* interval )
|
||||
{
|
||||
if ( !interval ) return;
|
||||
|
||||
size_t index = m_intervals.indexOf( insertBefore );
|
||||
if ( index < m_intervals.size() )
|
||||
m_intervals.insert( index, interval );
|
||||
else
|
||||
m_intervals.push_back( interval );
|
||||
|
||||
sortIntervalsByMD();
|
||||
updateConnectedEditors();
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2025 Equinor ASA
|
||||
//
|
||||
// ResInsight is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma once
|
||||
|
||||
#include "RiaDefines.h"
|
||||
|
||||
#include "cafPdmChildArrayField.h"
|
||||
#include "cafPdmObject.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class RimCustomSegmentInterval;
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
/// Collection to manage custom segment intervals for measured depth ranges
|
||||
///
|
||||
//==================================================================================================
|
||||
class RimCustomSegmentIntervalCollection : public caf::PdmObject
|
||||
{
|
||||
CAF_PDM_HEADER_INIT;
|
||||
|
||||
public:
|
||||
RimCustomSegmentIntervalCollection();
|
||||
~RimCustomSegmentIntervalCollection() override;
|
||||
|
||||
// Collection management
|
||||
std::vector<RimCustomSegmentInterval*> intervals() const;
|
||||
void addInterval( RimCustomSegmentInterval* interval );
|
||||
void insertInterval( RimCustomSegmentInterval* insertBefore, RimCustomSegmentInterval* interval );
|
||||
void removeInterval( RimCustomSegmentInterval* interval );
|
||||
void removeAllIntervals();
|
||||
|
||||
// Interval creation
|
||||
RimCustomSegmentInterval* createInterval( double startMD, double endMD );
|
||||
RimCustomSegmentInterval* createDefaultInterval();
|
||||
|
||||
// Lookup methods
|
||||
RimCustomSegmentInterval* findIntervalAtMD( double md ) const;
|
||||
|
||||
// Validation
|
||||
bool hasValidIntervals() const;
|
||||
bool hasOverlappingIntervals() const;
|
||||
std::vector<QString> validateIntervals() const;
|
||||
|
||||
// Sorting and organization
|
||||
void sortIntervalsByMD();
|
||||
|
||||
// Utility
|
||||
bool isEmpty() const;
|
||||
size_t count() const;
|
||||
void updateConnectedEditors();
|
||||
|
||||
// Accessor for UI integration
|
||||
caf::PdmChildArrayField<RimCustomSegmentInterval*>& intervalsField();
|
||||
|
||||
// Visual feedback for overlapping intervals
|
||||
void updateOverlapVisualFeedback();
|
||||
|
||||
protected:
|
||||
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
|
||||
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
|
||||
void defineCustomContextMenu( const caf::PdmFieldHandle* fieldNeedingMenu, QMenu* menu, QWidget* fieldEditorWidget ) override;
|
||||
void defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override;
|
||||
|
||||
private:
|
||||
void onChildDeleted( caf::PdmChildArrayFieldHandle* childArray, std::vector<caf::PdmObjectHandle*>& referringObjects ) override;
|
||||
|
||||
caf::PdmChildArrayField<RimCustomSegmentInterval*> m_intervals;
|
||||
};
|
||||
@@ -19,6 +19,8 @@
|
||||
#include "RimMswCompletionParameters.h"
|
||||
|
||||
#include "RiaEclipseUnitTools.h"
|
||||
#include "RimCustomSegmentInterval.h"
|
||||
#include "RimCustomSegmentIntervalCollection.h"
|
||||
#include "RimDiameterRoughnessIntervalCollection.h"
|
||||
|
||||
#include "RimWellPath.h"
|
||||
@@ -113,6 +115,12 @@ RimMswCompletionParameters::RimMswCompletionParameters()
|
||||
CAF_PDM_InitScriptableField( &m_enforceMaxSegmentLength, "EnforceMaxSegmentLength", false, "Enforce Max Segment Length" );
|
||||
CAF_PDM_InitScriptableField( &m_maxSegmentLength, "MaxSegmentLength", 200.0, "Max Segment Length" );
|
||||
m_maxSegmentLength.uiCapability()->setUiHidden( true );
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_customSegmentIntervals, "CustomSegmentIntervals", "Custom Segment Intervals" );
|
||||
m_customSegmentIntervals = new RimCustomSegmentIntervalCollection();
|
||||
m_customSegmentIntervals->intervalsField().uiCapability()->setUiEditorTypeName( caf::PdmUiTableViewEditor::uiEditorTypeName() );
|
||||
m_customSegmentIntervals->intervalsField().uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::TOP );
|
||||
m_customSegmentIntervals->intervalsField().uiCapability()->setCustomContextMenuEnabled( true );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -380,6 +388,44 @@ void RimMswCompletionParameters::setLengthAndDepth( LengthAndDepthType lengthAnd
|
||||
m_lengthAndDepth = lengthAndDepthType;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimCustomSegmentIntervalCollection* RimMswCompletionParameters::customSegmentIntervals() const
|
||||
{
|
||||
return m_customSegmentIntervals();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<std::pair<double, double>> RimMswCompletionParameters::getSegmentIntervals() const
|
||||
{
|
||||
std::vector<std::pair<double, double>> result;
|
||||
|
||||
if ( m_customSegmentIntervals() && !m_customSegmentIntervals()->isEmpty() )
|
||||
{
|
||||
auto intervals = m_customSegmentIntervals()->intervals();
|
||||
for ( auto* interval : intervals )
|
||||
{
|
||||
if ( interval && interval->isValidInterval() )
|
||||
{
|
||||
result.push_back( { interval->startMD(), interval->endMD() } );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RimMswCompletionParameters::hasCustomSegmentIntervals() const
|
||||
{
|
||||
return m_customSegmentIntervals() && !m_customSegmentIntervals()->isEmpty();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -450,8 +496,12 @@ void RimMswCompletionParameters::defineUiOrdering( QString uiConfigName, caf::Pd
|
||||
|
||||
uiOrdering.add( &m_pressureDrop );
|
||||
uiOrdering.add( &m_lengthAndDepth );
|
||||
uiOrdering.add( &m_enforceMaxSegmentLength );
|
||||
uiOrdering.add( &m_maxSegmentLength );
|
||||
|
||||
// Custom Segment Configuration section
|
||||
auto* segmentConfigGroup = uiOrdering.addNewGroup( "Custom Segment Configuration" );
|
||||
segmentConfigGroup->add( &m_enforceMaxSegmentLength );
|
||||
segmentConfigGroup->add( &m_maxSegmentLength );
|
||||
segmentConfigGroup->add( &m_customSegmentIntervals->intervalsField() );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -545,4 +595,15 @@ void RimMswCompletionParameters::defineCustomContextMenu( const caf::PdmFieldHan
|
||||
|
||||
menuBuilder.appendToMenu( menu );
|
||||
}
|
||||
|
||||
if ( fieldNeedingMenu == &m_customSegmentIntervals )
|
||||
{
|
||||
caf::CmdFeatureMenuBuilder menuBuilder;
|
||||
|
||||
menuBuilder << "RicNewCustomSegmentIntervalFeature";
|
||||
menuBuilder << "Separator";
|
||||
menuBuilder << "RicDeleteCustomSegmentIntervalFeature";
|
||||
|
||||
menuBuilder.appendToMenu( menu );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "cafPdmUiGroup.h"
|
||||
|
||||
class RimDiameterRoughnessIntervalCollection;
|
||||
class RimCustomSegmentIntervalCollection;
|
||||
|
||||
class RimMswCompletionParameters : public caf::PdmObject
|
||||
{
|
||||
@@ -93,6 +94,11 @@ public:
|
||||
|
||||
RimDiameterRoughnessIntervalCollection* diameterRoughnessIntervals() const;
|
||||
|
||||
// Custom segment intervals
|
||||
RimCustomSegmentIntervalCollection* customSegmentIntervals() const;
|
||||
std::vector<std::pair<double, double>> getSegmentIntervals() const;
|
||||
bool hasCustomSegmentIntervals() const;
|
||||
|
||||
void setUnitSystemSpecificDefaults();
|
||||
|
||||
void updateFromTopLevelWell( const RimMswCompletionParameters* topLevelWellParameters );
|
||||
@@ -125,4 +131,6 @@ private:
|
||||
|
||||
caf::PdmField<bool> m_enforceMaxSegmentLength;
|
||||
caf::PdmField<double> m_maxSegmentLength;
|
||||
|
||||
caf::PdmChildField<RimCustomSegmentIntervalCollection*> m_customSegmentIntervals;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user