mirror of
https://github.com/OPM/ResInsight.git
synced 2026-10-30 09:00:20 -05:00
CellFilters: Add combined filter for mixing cell and property filters
Add RimCombinedFilter, a node placed under the Eclipse property-filter collection that holds child filters (cell or property) and combines their results with a user-chosen AND or OR mode. Supports nesting and is exposed to Python via the generated rips CombinedFilter class. To let the same evaluation machinery handle any filter type, introduce a unified applyToCellVisibility(cellVis, grid, timeStep) virtual on RimCellFilter with a default implementation that bridges the existing range/index dispatch. RimEclipsePropertyFilter overrides it with the body extracted from RivReservoirViewPartMgr::computePropertyVisibility, which collapses to a generic per-child call and preserves the prior behavior for ordinary property filters. Loosen RimEclipsePropertyFilterCollection::m_propertyFilters to PdmChildArrayField<RimCellFilter*>, keeping the XML tag "PropertyFilters" and the typed propertyFilters() accessor. Add recursive helpers (hasActiveEvaluatableDescendant, hasActiveDynamicPropertyDescendant, hasActiveFormationNamesPropertyDescendant) so hasActiveFilters, hasActiveDynamicFilters and isUsingFormationNames see property filters nested inside a combined filter. Bridge filter changes inside a combined filter to updateDisplayModelNotifyManagedViews, since the property-filter collection doesn't subscribe to filterChanged signals. The existing RicNew* cell-filter creation features now route the new child into a selected combined filter when one is selected, otherwise into the top-level cell-filter collection as before. The combined filter's context menu offers the full mixed set: property, polygon, range, index, user-defined, and nested combined filter.
This commit is contained in:
1 parent
b27199f4ba
commit
9d5a8c28f4
23 files changed
+1188
-119
No files matched your search
@@ -2,6 +2,7 @@ set(SOURCE_GROUP_HEADER_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimCellFilter.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimCellFilterCollection.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimCellRangeFilter.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimCombinedFilter.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimPropertyFilter.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimPropertyFilterCollection.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimEclipsePropertyFilter.h
|
||||
@@ -19,6 +20,7 @@ set(SOURCE_GROUP_SOURCE_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimCellFilter.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimCellFilterCollection.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimCellRangeFilter.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimCombinedFilter.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimPropertyFilter.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimPropertyFilterCollection.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimEclipsePropertyFilter.cpp
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include "RimCellFilter.h"
|
||||
|
||||
#include "RigGridBase.h"
|
||||
#include "RigReservoirGridTools.h"
|
||||
#include "Rim3dView.h"
|
||||
#include "RimCase.h"
|
||||
@@ -302,6 +303,83 @@ QList<caf::PdmOptionItemInfo> RimCellFilter::calculateValueOptions( const caf::P
|
||||
return options;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCellFilter::applyToCellVisibility( cvf::UByteArray* cellVisibility, const RigGridBase* grid, size_t /*timeStepIndex*/ )
|
||||
{
|
||||
if ( cellVisibility == nullptr || grid == nullptr ) return;
|
||||
|
||||
const size_t n = cellVisibility->size();
|
||||
if ( n == 0 ) return;
|
||||
|
||||
// Determine which cells are "in this filter's set" — independent of the filter's INCLUDE/EXCLUDE mode.
|
||||
cvf::UByteArray inSet( n );
|
||||
inSet.setAll( 0 );
|
||||
|
||||
const int gIndx = static_cast<int>( grid->gridIndex() );
|
||||
|
||||
if ( isRangeFilter() )
|
||||
{
|
||||
// updateCompundFilter is a no-op when the range filter targets a different grid than the
|
||||
// one being evaluated. Skip the cellVisibility mutation entirely so LGR cells are not
|
||||
// erroneously blanked by a main-grid-targeted filter (legacy: parentGridVisibilities).
|
||||
if ( gridIndex() != gIndx ) return;
|
||||
|
||||
cvf::CellRangeFilter rf;
|
||||
updateCompundFilter( &rf, gIndx );
|
||||
|
||||
const bool isSubGrid = !grid->isMainGrid();
|
||||
|
||||
for ( size_t cellIdx = 0; cellIdx < n; ++cellIdx )
|
||||
{
|
||||
size_t i = 0, j = 0, k = 0;
|
||||
if ( grid->ijkFromCellIndex( cellIdx, &i, &j, &k ) )
|
||||
{
|
||||
// isCellVisible returns false when there are no include ranges (pure EXCLUDE
|
||||
// mode), so also consult isCellExcluded to mark those cells as "in the set".
|
||||
if ( rf.isCellVisible( i, j, k, isSubGrid ) || rf.isCellExcluded( i, j, k, isSubGrid ) )
|
||||
{
|
||||
inSet[cellIdx] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( isIndexFilter() )
|
||||
{
|
||||
// updateCellIndexFilter writes into include[] for INCLUDE-mode filters and exclude[] for
|
||||
// EXCLUDE-mode filters. A cell is "in the set" iff either array was mutated at that index.
|
||||
cvf::UByteArray incArr( n );
|
||||
cvf::UByteArray excArr( n );
|
||||
incArr.setAll( 0 );
|
||||
excArr.setAll( 1 );
|
||||
updateCellIndexFilter( &incArr, &excArr, gIndx );
|
||||
for ( size_t i = 0; i < n; ++i )
|
||||
{
|
||||
if ( incArr[i] || !excArr[i] ) inSet[i] = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unknown/property — subclass must override applyToCellVisibility. Default to no-op.
|
||||
return;
|
||||
}
|
||||
|
||||
const bool isInclude = ( filterMode() == INCLUDE );
|
||||
for ( size_t i = 0; i < n; ++i )
|
||||
{
|
||||
const bool in = ( inSet[i] != 0 );
|
||||
if ( isInclude )
|
||||
{
|
||||
if ( !in ) ( *cellVisibility )[i] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( in ) ( *cellVisibility )[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -37,6 +37,7 @@ class CellRangeFilter;
|
||||
class RimGeoMechCase;
|
||||
class RimEclipseCase;
|
||||
class RimCase;
|
||||
class RigGridBase;
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
@@ -93,6 +94,11 @@ public:
|
||||
virtual QString fullName() const;
|
||||
virtual void onGridChanged() {};
|
||||
|
||||
// Unified evaluation: take an incoming per-cell visibility mask and hide the cells that
|
||||
// this filter rejects (respecting its own INCLUDE/EXCLUDE mode). The default implementation
|
||||
// bridges the legacy range/index dispatch so existing subclasses do not need to override.
|
||||
virtual void applyToCellVisibility( cvf::UByteArray* cellVisibility, const RigGridBase* grid, size_t timeStepIndex );
|
||||
|
||||
protected:
|
||||
caf::PdmFieldHandle* userDescriptionField() override;
|
||||
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
|
||||
|
||||
@@ -0,0 +1,538 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2026 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 "RimCombinedFilter.h"
|
||||
|
||||
#include "RigGridBase.h"
|
||||
#include "RigReservoirGridTools.h"
|
||||
#include "RimCase.h"
|
||||
#include "RimCellIndexFilter.h"
|
||||
#include "RimCellRangeFilter.h"
|
||||
#include "RimPolygonFilter.h"
|
||||
#include "RimUserDefinedFilter.h"
|
||||
#include "RimUserDefinedIndexFilter.h"
|
||||
|
||||
#include "Polygons/RimPolygon.h"
|
||||
#include "Polygons/RimPolygonCollection.h"
|
||||
#include "RiaResultNames.h"
|
||||
#include "RimEclipsePropertyFilter.h"
|
||||
#include "RimEclipsePropertyFilterCollection.h"
|
||||
#include "RimEclipseResultDefinition.h"
|
||||
#include "RimTools.h"
|
||||
|
||||
#include "cafCmdFeatureMenuBuilder.h"
|
||||
#include "cafPdmFieldReorderCapability.h"
|
||||
#include "cafPdmFieldScriptingCapability.h"
|
||||
#include "cafPdmObjectScriptingCapability.h"
|
||||
|
||||
CAF_PDM_SOURCE_INIT( RimCombinedFilter, "CombinedFilter" );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimCombinedFilter::RimCombinedFilter()
|
||||
: RimCellFilter( FilterDefinitionType::INDEX )
|
||||
{
|
||||
CAF_PDM_InitScriptableObject( "Combined Filter", ":/CellFilter.png" );
|
||||
|
||||
setName( "Combined Filter" );
|
||||
|
||||
CAF_PDM_InitScriptableFieldNoDefault( &m_filters, "Filters", "Filters" );
|
||||
caf::PdmFieldReorderCapability::addToField( &m_filters );
|
||||
|
||||
CAF_PDM_InitScriptableFieldNoDefault( &m_combineMode, "CombineMode", "Combine Mode" );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimCombinedFilter::~RimCombinedFilter() = default;
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCombinedFilter::setCase( RimCase* srcCase )
|
||||
{
|
||||
RimCellFilter::setCase( srcCase );
|
||||
for ( RimCellFilter* child : m_filters )
|
||||
{
|
||||
if ( child ) child->setCase( srcCase );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RimCombinedFilter::isFilterEnabled() const
|
||||
{
|
||||
if ( !isActive() ) return false;
|
||||
|
||||
for ( RimCellFilter* child : m_filters )
|
||||
{
|
||||
if ( child && child->isFilterEnabled() ) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCombinedFilter::onGridChanged()
|
||||
{
|
||||
for ( RimCellFilter* child : m_filters )
|
||||
{
|
||||
if ( child ) child->onGridChanged();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Evaluate each enabled child to its own per-cell mask (each child respects its own
|
||||
/// INCLUDE/EXCLUDE mode inside applyToCellVisibility), AND/OR combine the masks, then apply this
|
||||
/// combined filter's INCLUDE/EXCLUDE mode onto the incoming cellVisibility.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCombinedFilter::applyToCellVisibility( cvf::UByteArray* cellVisibility, const RigGridBase* grid, size_t timeStepIndex )
|
||||
{
|
||||
if ( cellVisibility == nullptr || grid == nullptr ) return;
|
||||
|
||||
const size_t n = cellVisibility->size();
|
||||
if ( n == 0 ) return;
|
||||
|
||||
std::vector<RimCellFilter*> enabledChildren;
|
||||
for ( RimCellFilter* child : m_filters )
|
||||
{
|
||||
if ( child && child->isFilterEnabled() ) enabledChildren.push_back( child );
|
||||
}
|
||||
if ( enabledChildren.empty() ) return;
|
||||
|
||||
cvf::UByteArray combined( n );
|
||||
combined.setAll( m_combineMode() == CombineMode::AND ? 1 : 0 );
|
||||
|
||||
for ( RimCellFilter* child : enabledChildren )
|
||||
{
|
||||
cvf::UByteArray childMask( n );
|
||||
childMask.setAll( 1 );
|
||||
child->applyToCellVisibility( &childMask, grid, timeStepIndex );
|
||||
|
||||
if ( m_combineMode() == CombineMode::AND )
|
||||
{
|
||||
for ( size_t i = 0; i < n; ++i )
|
||||
combined[i] = combined[i] && childMask[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( size_t i = 0; i < n; ++i )
|
||||
combined[i] = combined[i] || childMask[i];
|
||||
}
|
||||
}
|
||||
|
||||
const bool isInclude = ( filterMode() == INCLUDE );
|
||||
for ( size_t i = 0; i < n; ++i )
|
||||
{
|
||||
if ( isInclude )
|
||||
{
|
||||
if ( !combined[i] ) ( *cellVisibility )[i] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( combined[i] ) ( *cellVisibility )[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Bridge for the cell-filter collection's legacy index-based dispatch. Combined filters normally
|
||||
/// live under the property-filter collection, but this override exists to keep the class usable if
|
||||
/// a future caller places one in the cell-filter collection. Builds a per-cell mask by running
|
||||
/// applyToCellVisibility against an all-visible scratch array, then folds the result into the
|
||||
/// collection's include/exclude arrays respecting this filter's INCLUDE/EXCLUDE mode.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCombinedFilter::updateCellIndexFilter( cvf::UByteArray* includeVisibility, cvf::UByteArray* excludeVisibility, int gridIndex )
|
||||
{
|
||||
if ( includeVisibility == nullptr || excludeVisibility == nullptr ) return;
|
||||
|
||||
auto* sourceCase = m_srcCase();
|
||||
if ( !sourceCase ) return;
|
||||
|
||||
const auto* structGrid = RigReservoirGridTools::gridByIndex( sourceCase, gridIndex );
|
||||
const auto* grid = dynamic_cast<const RigGridBase*>( structGrid );
|
||||
if ( grid == nullptr ) return;
|
||||
|
||||
const size_t n = includeVisibility->size();
|
||||
if ( n == 0 ) return;
|
||||
|
||||
cvf::UByteArray scratch( n );
|
||||
scratch.setAll( 1 );
|
||||
applyToCellVisibility( &scratch, grid, 0 );
|
||||
|
||||
if ( filterMode() == INCLUDE )
|
||||
{
|
||||
for ( size_t i = 0; i < n; ++i )
|
||||
if ( scratch[i] ) ( *includeVisibility )[i] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( size_t i = 0; i < n; ++i )
|
||||
if ( !scratch[i] ) ( *excludeVisibility )[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RimCombinedFilter::fullName() const
|
||||
{
|
||||
const QString modeStr = ( m_combineMode() == CombineMode::AND ) ? "AND" : "OR";
|
||||
return QString( "%1 [%2: %3]" ).arg( name() ).arg( modeStr ).arg( m_filters.size() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCombinedFilter::addFilter( RimCellFilter* child )
|
||||
{
|
||||
if ( !child ) return;
|
||||
if ( wouldCreateCycle( child ) ) return;
|
||||
m_filters.push_back( child );
|
||||
child->setCase( m_srcCase() );
|
||||
child->filterChanged.connect( this, &RimCombinedFilter::onChildFilterChanged );
|
||||
updateConnectedEditors();
|
||||
triggerFilterChanged();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCombinedFilter::removeFilter( RimCellFilter* child )
|
||||
{
|
||||
if ( !child ) return;
|
||||
m_filters.removeChild( child );
|
||||
triggerFilterChanged();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<RimCellFilter*> RimCombinedFilter::filters() const
|
||||
{
|
||||
return m_filters.childrenByType();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimCellRangeFilter* RimCombinedFilter::addNewCellRangeFilter( RimCase* srcCase, int gridIndex, int sliceDirection, int defaultSlice )
|
||||
{
|
||||
auto* f = new RimCellRangeFilter();
|
||||
addFilter( f );
|
||||
f->setCase( srcCase );
|
||||
f->setGridIndex( gridIndex );
|
||||
f->setDefaultValues( sliceDirection, defaultSlice );
|
||||
return f;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimPolygonFilter* RimCombinedFilter::addNewPolygonFilter( RimCase* srcCase, RimPolygon* polygon )
|
||||
{
|
||||
auto* f = new RimPolygonFilter();
|
||||
addFilter( f );
|
||||
f->setCase( srcCase );
|
||||
f->setPolygon( polygon );
|
||||
f->configurePolygonEditor();
|
||||
if ( polygon )
|
||||
{
|
||||
f->enableFilter( true );
|
||||
}
|
||||
else
|
||||
{
|
||||
f->enablePicking( true );
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimCellIndexFilter* RimCombinedFilter::addNewCellIndexFilter( RimCase* srcCase )
|
||||
{
|
||||
auto* f = new RimCellIndexFilter();
|
||||
addFilter( f );
|
||||
f->setCase( srcCase );
|
||||
return f;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimUserDefinedFilter* RimCombinedFilter::addNewUserDefinedFilter( RimCase* srcCase )
|
||||
{
|
||||
auto* f = new RimUserDefinedFilter();
|
||||
addFilter( f );
|
||||
f->setCase( srcCase );
|
||||
return f;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimUserDefinedIndexFilter* RimCombinedFilter::addNewUserDefinedIndexFilter( RimCase* srcCase, const std::vector<size_t>& defCellIndexes )
|
||||
{
|
||||
auto* f = new RimUserDefinedIndexFilter();
|
||||
addFilter( f );
|
||||
f->setCase( srcCase );
|
||||
f->setCellIndexes( defCellIndexes );
|
||||
return f;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimCombinedFilter* RimCombinedFilter::addNewCombinedFilter( RimCase* srcCase )
|
||||
{
|
||||
auto* f = new RimCombinedFilter();
|
||||
addFilter( f );
|
||||
f->setCase( srcCase );
|
||||
return f;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCombinedFilter::setCombineMode( CombineMode mode )
|
||||
{
|
||||
m_combineMode = mode;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimCombinedFilter::CombineMode RimCombinedFilter::combineMode() const
|
||||
{
|
||||
return m_combineMode();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCombinedFilter::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
|
||||
{
|
||||
uiOrdering.add( nameField() );
|
||||
auto* group = uiOrdering.addNewGroup( "General" );
|
||||
group->add( &m_filterMode );
|
||||
group->add( &m_combineMode );
|
||||
uiOrdering.skipRemainingFields( true );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCombinedFilter::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName )
|
||||
{
|
||||
PdmObject::defineUiTreeOrdering( uiTreeOrdering, uiConfigName );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCombinedFilter::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
|
||||
{
|
||||
updateIconState();
|
||||
triggerFilterChanged();
|
||||
notifyHostCollection();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Called by CAF when a new object is pushed into m_filters (e.g. via our factory methods or via
|
||||
/// drag-and-drop). Propagate so the host collection regenerates geometry.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCombinedFilter::onChildAdded( caf::PdmFieldHandle* /*containerForNewObject*/ )
|
||||
{
|
||||
triggerFilterChanged();
|
||||
notifyHostCollection();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Combined filters live only under the Eclipse property-filter collection, which triggers view
|
||||
/// regen via an explicit updateDisplayModelNotifyManagedViews() call rather than by subscribing to
|
||||
/// filterChanged. Call that API directly so our edits propagate.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCombinedFilter::notifyHostCollection()
|
||||
{
|
||||
if ( auto* propColl = firstAncestorOrThisOfType<RimEclipsePropertyFilterCollection>() )
|
||||
{
|
||||
propColl->updateDisplayModelNotifyManagedViews( nullptr );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Called after reading from a project file. Re-wire child filterChanged signals so edits made to
|
||||
/// deserialized children propagate up.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCombinedFilter::initAfterRead()
|
||||
{
|
||||
RimCellFilter::initAfterRead();
|
||||
for ( RimCellFilter* child : m_filters )
|
||||
{
|
||||
if ( child ) child->filterChanged.connect( this, &RimCombinedFilter::onChildFilterChanged );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Propagate a child's change up so the view re-renders.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCombinedFilter::onChildFilterChanged( const caf::SignalEmitter* /*emitter*/ )
|
||||
{
|
||||
triggerFilterChanged();
|
||||
notifyHostCollection();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Any enabled child that the combined filter would actually evaluate. Property-filter children
|
||||
/// also need a loaded result; other cell filters are always evaluatable when enabled.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RimCombinedFilter::hasActiveEvaluatableDescendant() const
|
||||
{
|
||||
for ( RimCellFilter* child : m_filters )
|
||||
{
|
||||
if ( !child || !child->isFilterEnabled() ) continue;
|
||||
|
||||
if ( auto* ep = dynamic_cast<RimEclipsePropertyFilter*>( child ) )
|
||||
{
|
||||
if ( ep->resultDefinition() && ep->resultDefinition()->hasResult() ) return true;
|
||||
continue;
|
||||
}
|
||||
if ( auto* nested = dynamic_cast<RimCombinedFilter*>( child ) )
|
||||
{
|
||||
if ( nested->hasActiveEvaluatableDescendant() ) return true;
|
||||
continue;
|
||||
}
|
||||
// Range, polygon, index, user-defined — evaluatable whenever enabled.
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// True if any active descendant is an Eclipse property filter backed by a dynamic result. Drives
|
||||
/// per-time-step cell-visibility cache invalidation in RimGridView.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RimCombinedFilter::hasActiveDynamicPropertyDescendant() const
|
||||
{
|
||||
for ( RimCellFilter* child : m_filters )
|
||||
{
|
||||
if ( !child || !child->isFilterEnabled() ) continue;
|
||||
|
||||
if ( auto* ep = dynamic_cast<RimEclipsePropertyFilter*>( child ) )
|
||||
{
|
||||
if ( ep->resultDefinition() && ep->resultDefinition()->hasDynamicResult() ) return true;
|
||||
}
|
||||
else if ( auto* nested = dynamic_cast<RimCombinedFilter*>( child ) )
|
||||
{
|
||||
if ( nested->hasActiveDynamicPropertyDescendant() ) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// True if any active descendant is a formation-names property filter. Matches the collection-level
|
||||
/// isUsingFormationNames() check.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RimCombinedFilter::hasActiveFormationNamesPropertyDescendant() const
|
||||
{
|
||||
for ( RimCellFilter* child : m_filters )
|
||||
{
|
||||
if ( !child || !child->isFilterEnabled() ) continue;
|
||||
|
||||
if ( auto* ep = dynamic_cast<RimEclipsePropertyFilter*>( child ) )
|
||||
{
|
||||
auto* rd = ep->resultDefinition();
|
||||
if ( rd && rd->resultType() == RiaDefines::ResultCatType::FORMATION_NAMES &&
|
||||
rd->resultVariable() != RiaResultNames::undefinedResultName() )
|
||||
return true;
|
||||
}
|
||||
else if ( auto* nested = dynamic_cast<RimCombinedFilter*>( child ) )
|
||||
{
|
||||
if ( nested->hasActiveFormationNamesPropertyDescendant() ) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Right-click "add child" menu on the combined filter. Since combined filters only live under the
|
||||
/// Eclipse property-filter collection, the menu always offers the full mixed-type set: property
|
||||
/// filter, polygon, ranges, index, user-defined, and a nested combined filter.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimCombinedFilter::appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const
|
||||
{
|
||||
menuBuilder << "RicEclipsePropertyFilterNewFeature";
|
||||
menuBuilder << "Separator";
|
||||
|
||||
menuBuilder.subMenuStart( "Polygon Filter", QIcon( ":/CellFilter_Polygon.png" ) );
|
||||
{
|
||||
auto polygonCollection = RimTools::polygonCollection();
|
||||
if ( polygonCollection )
|
||||
{
|
||||
for ( auto p : polygonCollection->allPolygons() )
|
||||
{
|
||||
if ( !p ) continue;
|
||||
menuBuilder.addCmdFeatureWithUserData( "RicNewPolygonFilterFeature", p->name(), QVariant::fromValue( static_cast<void*>( p ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
menuBuilder.subMenuEnd();
|
||||
|
||||
menuBuilder << "RicNewPolygonFilterFeature";
|
||||
menuBuilder << "Separator";
|
||||
menuBuilder.subMenuStart( "Range Filter" );
|
||||
menuBuilder << "RicNewRangeFilterSliceIFeature";
|
||||
menuBuilder << "RicNewRangeFilterSliceJFeature";
|
||||
menuBuilder << "RicNewRangeFilterSliceKFeature";
|
||||
menuBuilder << "RicNewCellRangeFilterFeature";
|
||||
menuBuilder.subMenuEnd();
|
||||
menuBuilder << "RicNewCellIndexFilterFeature";
|
||||
menuBuilder << "Separator";
|
||||
menuBuilder << "RicNewUserDefinedFilterFeature";
|
||||
menuBuilder << "RicNewUserDefinedIndexFilterFeature";
|
||||
menuBuilder << "Separator";
|
||||
menuBuilder << "RicEclipseCombinedPropertyFilterNewFeature";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Refuse additions that would create a cycle: candidate must not be `this`, and if candidate is a
|
||||
/// combined filter, `this` must not appear anywhere in its subtree.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RimCombinedFilter::wouldCreateCycle( RimCellFilter* candidate ) const
|
||||
{
|
||||
if ( candidate == this ) return true;
|
||||
|
||||
auto* candidateCombined = dynamic_cast<RimCombinedFilter*>( candidate );
|
||||
if ( !candidateCombined ) return false;
|
||||
|
||||
for ( RimCellFilter* grandchild : candidateCombined->filters() )
|
||||
{
|
||||
if ( grandchild == this ) return true;
|
||||
if ( auto* gcCombined = dynamic_cast<RimCombinedFilter*>( grandchild ) )
|
||||
{
|
||||
if ( wouldCreateCycle( gcCombined ) ) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2026 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 "RimCellFilter.h"
|
||||
#include "RimCellFilterCollection.h"
|
||||
|
||||
#include "cafAppEnum.h"
|
||||
#include "cafPdmChildArrayField.h"
|
||||
#include "cafPdmField.h"
|
||||
|
||||
class RimCellIndexFilter;
|
||||
class RimCellRangeFilter;
|
||||
class RimPolygon;
|
||||
class RimPolygonFilter;
|
||||
class RimUserDefinedFilter;
|
||||
class RimUserDefinedIndexFilter;
|
||||
|
||||
//==================================================================================================
|
||||
/// A filter whose result is a boolean combination (AND / OR) of its child filters' results.
|
||||
/// Child filters are evaluated to per-cell masks (each respecting its own INCLUDE/EXCLUDE mode),
|
||||
/// then combined. The combined filter's own INCLUDE/EXCLUDE mode is applied to the output.
|
||||
/// Nesting is supported — a combined filter may contain other combined filters. Lives only inside
|
||||
/// RimEclipsePropertyFilterCollection; that's the one collection whose evaluation pipeline supplies
|
||||
/// a time step, which is required for property-filter children.
|
||||
//==================================================================================================
|
||||
class RimCombinedFilter : public RimCellFilter
|
||||
{
|
||||
CAF_PDM_HEADER_INIT;
|
||||
|
||||
public:
|
||||
using CombineMode = RimCellFilterCollection::CombineFilterModeType;
|
||||
|
||||
RimCombinedFilter();
|
||||
~RimCombinedFilter() override;
|
||||
|
||||
void setCase( RimCase* srcCase ) override;
|
||||
bool isFilterEnabled() const override;
|
||||
void onGridChanged() override;
|
||||
|
||||
void applyToCellVisibility( cvf::UByteArray* cellVisibility, const RigGridBase* grid, size_t timeStepIndex ) override;
|
||||
|
||||
// Bridge from legacy collection dispatch: combined filter is declared INDEX-type, so the cell
|
||||
// filter collection's evaluation path (if ever called) would route through updateCellIndexFilter.
|
||||
void updateCompundFilter( cvf::CellRangeFilter*, int ) override {}
|
||||
void updateCellIndexFilter( cvf::UByteArray* includeVisibility, cvf::UByteArray* excludeVisibility, int gridIndex ) override;
|
||||
|
||||
QString fullName() const override;
|
||||
|
||||
void addFilter( RimCellFilter* child );
|
||||
void removeFilter( RimCellFilter* child );
|
||||
std::vector<RimCellFilter*> filters() const;
|
||||
|
||||
// Recursive introspection helpers — used by the property-filter collection so that a combined
|
||||
// filter sitting in that collection can report whether it has evaluation-worthy descendants.
|
||||
bool hasActiveEvaluatableDescendant() const;
|
||||
bool hasActiveDynamicPropertyDescendant() const;
|
||||
bool hasActiveFormationNamesPropertyDescendant() const;
|
||||
|
||||
// Typed factory methods — mirror the ones on RimCellFilterCollection so features can add
|
||||
// children of the correct type directly.
|
||||
RimCellRangeFilter* addNewCellRangeFilter( RimCase* srcCase, int gridIndex, int sliceDirection = -1, int defaultSlice = -1 );
|
||||
RimPolygonFilter* addNewPolygonFilter( RimCase* srcCase, RimPolygon* polygon );
|
||||
RimCellIndexFilter* addNewCellIndexFilter( RimCase* srcCase );
|
||||
RimUserDefinedFilter* addNewUserDefinedFilter( RimCase* srcCase );
|
||||
RimUserDefinedIndexFilter* addNewUserDefinedIndexFilter( RimCase* srcCase, const std::vector<size_t>& defCellIndexes = {} );
|
||||
RimCombinedFilter* addNewCombinedFilter( RimCase* srcCase );
|
||||
|
||||
void setCombineMode( CombineMode mode );
|
||||
CombineMode combineMode() const;
|
||||
|
||||
protected:
|
||||
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
|
||||
void defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName ) override;
|
||||
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
|
||||
void initAfterRead() override;
|
||||
void appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const override;
|
||||
void onChildAdded( caf::PdmFieldHandle* containerForNewObject ) override;
|
||||
|
||||
private:
|
||||
bool wouldCreateCycle( RimCellFilter* candidate ) const;
|
||||
void onChildFilterChanged( const caf::SignalEmitter* emitter );
|
||||
|
||||
// Combined filters only sit inside RimEclipsePropertyFilterCollection, which doesn't use
|
||||
// filterChanged signals — it requires an explicit updateDisplayModelNotifyManagedViews() call
|
||||
// to trigger a view regen. This helper performs that call.
|
||||
void notifyHostCollection();
|
||||
|
||||
caf::PdmChildArrayField<RimCellFilter*> m_filters;
|
||||
caf::PdmField<caf::AppEnum<CombineMode>> m_combineMode;
|
||||
};
|
||||
@@ -30,6 +30,9 @@
|
||||
#include "RigEclipseResultAddress.h"
|
||||
#include "RigFlowDiagResults.h"
|
||||
#include "RigFormationNames.h"
|
||||
#include "RigGridBase.h"
|
||||
#include "RigResultAccessor.h"
|
||||
#include "RigResultAccessorFactory.h"
|
||||
|
||||
#include "RimEclipseCase.h"
|
||||
#include "RimEclipsePropertyFilterCollection.h"
|
||||
@@ -698,6 +701,93 @@ void RimEclipsePropertyFilter::initAfterRead()
|
||||
updateIconState();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Evaluate this property filter against the incoming cell visibility mask. Only cells that
|
||||
/// are currently visible are considered; non-matching cells are flipped to invisible according
|
||||
/// to the INCLUDE/EXCLUDE mode. This is a generic hook the renderer uses to treat every filter
|
||||
/// uniformly; the body is extracted from the former inline loop in
|
||||
/// RivReservoirViewPartMgr::computePropertyVisibility.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimEclipsePropertyFilter::applyToCellVisibility( cvf::UByteArray* cellVisibility, const RigGridBase* grid, size_t timeStepIndex )
|
||||
{
|
||||
if ( cellVisibility == nullptr || grid == nullptr ) return;
|
||||
if ( !isActive() || !resultDefinition()->hasResult() ) return;
|
||||
|
||||
resultDefinition()->loadResult();
|
||||
|
||||
auto* container = parentContainer();
|
||||
if ( !container ) return;
|
||||
auto* view = container->reservoirView();
|
||||
if ( !view || !view->eclipseCase() ) return;
|
||||
RigEclipseCaseData* eclipseCase = view->eclipseCase()->eclipseCaseData();
|
||||
if ( !eclipseCase ) return;
|
||||
|
||||
cvf::ref<RigResultAccessor> resultAccessor =
|
||||
RigResultAccessorFactory::createFromResultDefinition( eclipseCase, grid->gridIndex(), timeStepIndex, resultDefinition() );
|
||||
|
||||
CVF_ASSERT( resultAccessor.notNull() );
|
||||
|
||||
const RimCellFilter::FilterModeType filterType = filterMode();
|
||||
|
||||
if ( isCategorySelectionActive() )
|
||||
{
|
||||
std::vector<int> integerVector = selectedCategoryValues();
|
||||
std::set<int> integerSet( integerVector.begin(), integerVector.end() );
|
||||
|
||||
for ( int cellIndex = 0; cellIndex < static_cast<int>( grid->cellCount() ); cellIndex++ )
|
||||
{
|
||||
if ( ( *cellVisibility )[cellIndex] )
|
||||
{
|
||||
size_t resultValueIndex = cellIndex;
|
||||
double scalarValue = resultAccessor->cellScalar( resultValueIndex );
|
||||
if ( integerSet.find( static_cast<int>( scalarValue ) ) != integerSet.end() )
|
||||
{
|
||||
if ( filterType == RimCellFilter::EXCLUDE )
|
||||
{
|
||||
( *cellVisibility )[cellIndex] = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( filterType == RimCellFilter::INCLUDE )
|
||||
{
|
||||
( *cellVisibility )[cellIndex] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
double lowerBound = 0.0;
|
||||
double upperBound = 0.0;
|
||||
rangeValues( &lowerBound, &upperBound );
|
||||
|
||||
for ( int cellIndex = 0; cellIndex < static_cast<int>( grid->cellCount() ); cellIndex++ )
|
||||
{
|
||||
if ( ( *cellVisibility )[cellIndex] )
|
||||
{
|
||||
size_t resultValueIndex = cellIndex;
|
||||
double scalarValue = resultAccessor->cellScalar( resultValueIndex );
|
||||
if ( lowerBound <= scalarValue && scalarValue <= upperBound )
|
||||
{
|
||||
if ( filterType == RimCellFilter::EXCLUDE )
|
||||
{
|
||||
( *cellVisibility )[cellIndex] = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( filterType == RimCellFilter::INCLUDE )
|
||||
{
|
||||
( *cellVisibility )[cellIndex] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -57,6 +57,8 @@ public:
|
||||
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
|
||||
void initAfterRead() override;
|
||||
|
||||
void applyToCellVisibility( cvf::UByteArray* cellVisibility, const RigGridBase* grid, size_t timeStepIndex ) override;
|
||||
|
||||
void updateUiFieldsFromActiveResult();
|
||||
|
||||
std::map<QString, std::vector<caf::PdmFieldHandle*>> quickAccessFields() override;
|
||||
|
||||
+85
-16
@@ -22,6 +22,9 @@
|
||||
|
||||
#include "RiaResultNames.h"
|
||||
|
||||
#include "RimCellFilter.h"
|
||||
#include "RimCombinedFilter.h"
|
||||
#include "RimEclipseCase.h"
|
||||
#include "RimEclipseCellColors.h"
|
||||
#include "RimEclipsePropertyFilter.h"
|
||||
#include "RimEclipseResultDefinition.h"
|
||||
@@ -57,7 +60,7 @@ RimEclipseView* RimEclipsePropertyFilterCollection::reservoirView()
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimEclipsePropertyFilterCollection::setIsDuplicatedFromLinkedView()
|
||||
{
|
||||
for ( RimEclipsePropertyFilter* propertyFilter : m_propertyFilters )
|
||||
for ( RimEclipsePropertyFilter* propertyFilter : propertyFilters() )
|
||||
{
|
||||
propertyFilter->setIsDuplicatedFromLinkedView( true );
|
||||
}
|
||||
@@ -68,23 +71,36 @@ void RimEclipsePropertyFilterCollection::setIsDuplicatedFromLinkedView()
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<RimEclipsePropertyFilter*> RimEclipsePropertyFilterCollection::propertyFilters() const
|
||||
{
|
||||
return m_propertyFilters.childrenByType();
|
||||
std::vector<RimEclipsePropertyFilter*> typed;
|
||||
for ( RimCellFilter* f : m_propertyFilters )
|
||||
{
|
||||
if ( auto* ep = dynamic_cast<RimEclipsePropertyFilter*>( f ) ) typed.push_back( ep );
|
||||
}
|
||||
return typed;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
caf::PdmChildArrayField<RimEclipsePropertyFilter*>& RimEclipsePropertyFilterCollection::propertyFiltersField()
|
||||
caf::PdmChildArrayField<RimCellFilter*>& RimEclipsePropertyFilterCollection::propertyFiltersField()
|
||||
{
|
||||
return m_propertyFilters;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<RimCellFilter*> RimEclipsePropertyFilterCollection::filtersForEvaluation() const
|
||||
{
|
||||
return m_propertyFilters.childrenByType();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimEclipsePropertyFilterCollection::loadAndInitializePropertyFilters()
|
||||
{
|
||||
for ( RimEclipsePropertyFilter* propertyFilter : m_propertyFilters )
|
||||
for ( RimEclipsePropertyFilter* propertyFilter : propertyFilters() )
|
||||
{
|
||||
propertyFilter->resultDefinition()->setEclipseCase( reservoirView()->eclipseCase() );
|
||||
propertyFilter->initAfterRead();
|
||||
@@ -111,24 +127,47 @@ bool RimEclipsePropertyFilterCollection::hasActiveFilters() const
|
||||
{
|
||||
if ( !isActive ) return false;
|
||||
|
||||
for ( RimEclipsePropertyFilter* propertyFilter : m_propertyFilters )
|
||||
for ( RimCellFilter* filter : filtersForEvaluation() )
|
||||
{
|
||||
if ( propertyFilter->isActive() && propertyFilter->resultDefinition()->hasResult() ) return true;
|
||||
if ( !filter || !filter->isFilterEnabled() ) continue;
|
||||
|
||||
if ( auto* ep = dynamic_cast<RimEclipsePropertyFilter*>( filter ) )
|
||||
{
|
||||
if ( ep->resultDefinition() && ep->resultDefinition()->hasResult() ) return true;
|
||||
continue;
|
||||
}
|
||||
if ( auto* comp = dynamic_cast<RimCombinedFilter*>( filter ) )
|
||||
{
|
||||
if ( comp->hasActiveEvaluatableDescendant() ) return true;
|
||||
continue;
|
||||
}
|
||||
// Any other cell-filter subtype placed in this collection is evaluatable when enabled.
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Returns whether any of the active property filters are based on a dynamic result
|
||||
/// Returns whether any of the active property filters are based on a dynamic result. Includes
|
||||
/// property filters nested inside compound filters so time-step updates invalidate correctly.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RimEclipsePropertyFilterCollection::hasActiveDynamicFilters() const
|
||||
{
|
||||
if ( !isActive ) return false;
|
||||
|
||||
for ( RimEclipsePropertyFilter* propertyFilter : m_propertyFilters )
|
||||
for ( RimCellFilter* filter : filtersForEvaluation() )
|
||||
{
|
||||
if ( propertyFilter->isActive() && propertyFilter->resultDefinition()->hasDynamicResult() ) return true;
|
||||
if ( !filter || !filter->isFilterEnabled() ) continue;
|
||||
|
||||
if ( auto* ep = dynamic_cast<RimEclipsePropertyFilter*>( filter ) )
|
||||
{
|
||||
if ( ep->resultDefinition() && ep->resultDefinition()->hasDynamicResult() ) return true;
|
||||
}
|
||||
else if ( auto* comp = dynamic_cast<RimCombinedFilter*>( filter ) )
|
||||
{
|
||||
if ( comp->hasActiveDynamicPropertyDescendant() ) return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -141,11 +180,21 @@ bool RimEclipsePropertyFilterCollection::isUsingFormationNames() const
|
||||
{
|
||||
if ( !isActive ) return false;
|
||||
|
||||
for ( RimEclipsePropertyFilter* propertyFilter : m_propertyFilters )
|
||||
for ( RimCellFilter* filter : filtersForEvaluation() )
|
||||
{
|
||||
if ( propertyFilter->isActive() && propertyFilter->resultDefinition()->resultType() == RiaDefines::ResultCatType::FORMATION_NAMES &&
|
||||
propertyFilter->resultDefinition()->resultVariable() != RiaResultNames::undefinedResultName() )
|
||||
return true;
|
||||
if ( !filter || !filter->isFilterEnabled() ) continue;
|
||||
|
||||
if ( auto* ep = dynamic_cast<RimEclipsePropertyFilter*>( filter ) )
|
||||
{
|
||||
auto* rd = ep->resultDefinition();
|
||||
if ( rd && rd->resultType() == RiaDefines::ResultCatType::FORMATION_NAMES &&
|
||||
rd->resultVariable() != RiaResultNames::undefinedResultName() )
|
||||
return true;
|
||||
}
|
||||
else if ( auto* comp = dynamic_cast<RimCombinedFilter*>( filter ) )
|
||||
{
|
||||
if ( comp->hasActiveFormationNamesPropertyDescendant() ) return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -175,7 +224,7 @@ void RimEclipsePropertyFilterCollection::updateIconState()
|
||||
|
||||
updateUiIconFromState( activeIcon );
|
||||
|
||||
for ( RimEclipsePropertyFilter* cellFilter : m_propertyFilters )
|
||||
for ( RimEclipsePropertyFilter* cellFilter : propertyFilters() )
|
||||
{
|
||||
cellFilter->updateActiveState();
|
||||
cellFilter->updateIconState();
|
||||
@@ -187,7 +236,7 @@ void RimEclipsePropertyFilterCollection::updateIconState()
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimEclipsePropertyFilterCollection::updateFromCurrentTimeStep()
|
||||
{
|
||||
for ( RimEclipsePropertyFilter* cellFilter : m_propertyFilters() )
|
||||
for ( RimEclipsePropertyFilter* cellFilter : propertyFilters() )
|
||||
{
|
||||
cellFilter->updateFromCurrentTimeStep();
|
||||
}
|
||||
@@ -202,7 +251,7 @@ void RimEclipsePropertyFilterCollection::updateDefaultResult( const RimEclipseCe
|
||||
if ( m_propertyFilters.empty() ) return;
|
||||
|
||||
auto view = reservoirView();
|
||||
for ( auto filter : m_propertyFilters )
|
||||
for ( RimEclipsePropertyFilter* filter : propertyFilters() )
|
||||
{
|
||||
if ( !filter->isLinkedWithCellResult() ) continue;
|
||||
|
||||
@@ -243,4 +292,24 @@ void RimEclipsePropertyFilterCollection::appendMenuItems( caf::CmdFeatureMenuBui
|
||||
{
|
||||
menuBuilder << "RicEclipsePropertyFilterNewFeature";
|
||||
menuBuilder << "RicAddLinkedEclipsePropertyFilterFeature";
|
||||
menuBuilder << "Separator";
|
||||
menuBuilder << "RicEclipseCombinedPropertyFilterNewFeature";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimCombinedFilter* RimEclipsePropertyFilterCollection::addNewCombinedFilter()
|
||||
{
|
||||
auto* combined = new RimCombinedFilter();
|
||||
|
||||
auto view = reservoirView();
|
||||
if ( view && view->eclipseCase() )
|
||||
{
|
||||
combined->setCase( view->eclipseCase() );
|
||||
}
|
||||
|
||||
m_propertyFilters.push_back( combined );
|
||||
updateConnectedEditors();
|
||||
return combined;
|
||||
}
|
||||
+10
-3
@@ -24,6 +24,8 @@
|
||||
|
||||
#include "cafPdmChildArrayField.h"
|
||||
|
||||
class RimCellFilter;
|
||||
class RimCombinedFilter;
|
||||
class RimEclipsePropertyFilter;
|
||||
class RimEclipseView;
|
||||
class RimEclipseCellColors;
|
||||
@@ -42,8 +44,12 @@ public:
|
||||
RimEclipseView* reservoirView();
|
||||
void setIsDuplicatedFromLinkedView();
|
||||
|
||||
std::vector<RimEclipsePropertyFilter*> propertyFilters() const;
|
||||
caf::PdmChildArrayField<RimEclipsePropertyFilter*>& propertyFiltersField();
|
||||
std::vector<RimEclipsePropertyFilter*> propertyFilters() const;
|
||||
caf::PdmChildArrayField<RimCellFilter*>& propertyFiltersField();
|
||||
|
||||
// Returns all children as RimCellFilter*, including compound filters. Used by the
|
||||
// visualization pipeline to call applyToCellVisibility() uniformly.
|
||||
std::vector<RimCellFilter*> filtersForEvaluation() const;
|
||||
|
||||
bool hasActiveFilters() const override;
|
||||
bool hasActiveDynamicFilters() const override;
|
||||
@@ -56,11 +62,12 @@ public:
|
||||
|
||||
void updateDefaultResult( const RimEclipseCellColors* result );
|
||||
RimEclipsePropertyFilter* addFilterLinkedToCellResult();
|
||||
RimCombinedFilter* addNewCombinedFilter();
|
||||
|
||||
protected:
|
||||
void initAfterRead() override;
|
||||
void appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const override;
|
||||
|
||||
private:
|
||||
caf::PdmChildArrayField<RimEclipsePropertyFilter*> m_propertyFilters;
|
||||
caf::PdmChildArrayField<RimCellFilter*> m_propertyFilters;
|
||||
};
|
||||
Reference in new issue
Block a user