#14488 Surface and intersection improvements

Use I as the default direction when creating an IJK intersection, and center the fixed index on the I axis.

Allow multiselect of surfaces for a Surface Curve. The field keyword is changed from Surface1 to Surfaces, with a keyword alias so existing project files are read as before. One curve is drawn per selected surface, each with its own label and color.

Use the color defined in the Surfaces collection for Surface Band and Surface Curve. The color is shown as read only, and a Custom Color option allows the user to specify a color. Bands created from an ensemble surface keep the structural uncertainty colors, as the statistics surfaces share the same color.
This commit is contained in:
Magne Sjaastad
2026-08-10 12:38:02 +02:00
parent ff7bf6c7c9
commit b851801cfb
9 changed files with 192 additions and 38 deletions
@@ -78,7 +78,9 @@ void RicCreateSurfaceIntersectionBandFeature::onActionTriggered( bool isChecked
auto band = intersection->addIntersectionBand();
band->setSurfaces( surf1, surf2 );
// The statistics surfaces share the same color, use distinct colors to separate the bands
auto color = colors.cycledColor3f( 0 );
band->setUseCustomColor( true );
band->setBandColor( color );
band->setBandOpacity( defaultOpacity );
band->setPolygonOffsetUnit( 0.08 );
@@ -100,6 +102,7 @@ void RicCreateSurfaceIntersectionBandFeature::onActionTriggered( bool isChecked
band->setSurfaces( surf1, surf2 );
auto color = colors.cycledColor3f( 1 );
band->setUseCustomColor( true );
band->setBandColor( color );
band->setBandOpacity( defaultOpacity );
band->setPolygonOffsetUnit( 0.1 );
@@ -117,16 +120,13 @@ void RicCreateSurfaceIntersectionBandFeature::onActionTriggered( bool isChecked
if ( surfaces.size() > 1 )
{
// The color defined in the Surfaces collection is used for the band
band->setSurfaces( surfaces[0], surfaces[1] );
}
auto color = colors.cycledColor3f( 1 );
band->setBandColor( color );
band->setBandOpacity( defaultOpacity );
band->setPolygonOffsetUnit( 0.1 );
band->lineAppearance()->setColor( color );
objectToSelect = band;
}
@@ -169,7 +169,10 @@ std::vector<RimSurface*> RivSurfaceIntersectionCurveTools::referencedSurfaces( c
for ( auto curve : surfaceIntersections->surfaceIntersectionCurves() )
{
appendSurface( curve->surface() );
for ( auto surface : curve->surfaces() )
{
appendSurface( surface );
}
}
for ( auto band : surfaceIntersections->surfaceIntersectionBands() )
@@ -290,18 +293,21 @@ cvf::Collection<cvf::Part>
{
if ( !curve->isChecked() ) continue;
auto surface = curve->surface();
if ( !surface ) continue;
// One curve is created per selected surface, each with its own label and color
for ( auto surface : curve->surfaces() )
{
if ( !surface ) continue;
auto it = surfacePolylines.find( surface );
if ( it == surfacePolylines.end() ) continue;
auto it = surfacePolylines.find( surface );
if ( it == surfacePolylines.end() ) continue;
auto curveParts = createCurveParts( it->second,
surface->fullName(),
curve->lineAppearance()->color(),
curve->lineAppearance()->thickness(),
scaleTransform );
appendParts( curveParts );
auto curveParts = createCurveParts( it->second,
surface->fullName(),
curve->colorForSurface( surface ),
curve->lineAppearance()->thickness(),
scaleTransform );
appendParts( curveParts );
}
}
for ( auto band : surfaceIntersections->surfaceIntersectionBands() )
@@ -320,11 +326,11 @@ cvf::Collection<cvf::Part>
const auto& polylineB = it2->second;
auto curvePartsA =
createCurveParts( polylineA, surface1->fullName(), band->lineAppearance()->color(), band->lineAppearance()->thickness(), scaleTransform );
createCurveParts( polylineA, surface1->fullName(), band->lineColor(), band->lineAppearance()->thickness(), scaleTransform );
appendParts( curvePartsA );
auto curvePartsB =
createCurveParts( polylineB, surface2->fullName(), band->lineAppearance()->color(), band->lineAppearance()->thickness(), scaleTransform );
createCurveParts( polylineB, surface2->fullName(), band->lineColor(), band->lineAppearance()->thickness(), scaleTransform );
appendParts( curvePartsB );
auto bandPart = createBandPart( polylineA, polylineB, band->bandColor(), band->bandOpacity(), band->polygonOffsetUnit() );
@@ -85,6 +85,14 @@ void RimAnnotationLineAppearance::setLineFieldsHidden( bool hidden )
m_lineFieldsHidden = hidden;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimAnnotationLineAppearance::setColorReadOnly( bool readOnly )
{
m_color.uiCapability()->setUiReadOnly( readOnly );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -48,6 +48,7 @@ public:
RimAnnotationLineAppearance();
void setLineFieldsHidden( bool hidden );
void setColorReadOnly( bool readOnly );
void configureForSummaryAnnotations();
void setColor( const cvf::Color3f& newColor );
@@ -39,7 +39,7 @@ void AppEnum<RimIjkIntersection::GridAxis>::setUp()
addItem( RimIjkIntersection::GridAxis::AXIS_I, "AXIS_I", "I" );
addItem( RimIjkIntersection::GridAxis::AXIS_J, "AXIS_J", "J" );
addItem( RimIjkIntersection::GridAxis::AXIS_K, "AXIS_K", "K" );
setDefault( RimIjkIntersection::GridAxis::AXIS_K );
setDefault( RimIjkIntersection::GridAxis::AXIS_I );
}
} // namespace caf
@@ -193,14 +193,14 @@ void RimIjkIntersection::setToDefaultValues()
int nj = static_cast<int>( grid->cellCountJ() );
int nk = static_cast<int>( grid->cellCountK() );
m_axis = GridAxis::AXIS_K;
m_axis = GridAxis::AXIS_I;
m_iMin = 1;
m_iMax = ni;
m_jMin = 1;
m_jMax = nj;
m_kMin = 1;
m_kMax = nk;
m_fixedIndex = nk / 2 + 1;
m_fixedIndex = ni / 2 + 1;
}
//--------------------------------------------------------------------------------------------------
@@ -50,6 +50,8 @@ RimSurfaceIntersectionBand::RimSurfaceIntersectionBand()
m_lineAppearance->objectChanged.connect( this, &RimSurfaceIntersectionBand::onObjectChanged );
uiCapability()->setUiTreeChildrenHidden( true );
CAF_PDM_InitField( &m_useCustomColor, "UseCustomColor", false, "Custom Color" );
CAF_PDM_InitField( &m_bandColor, "BandColor", cvf::Color3f( cvf::Color3f::BLACK ), "Band Color" );
CAF_PDM_InitField( &m_bandOpacity, "BandOpacity", 0.8, "Band Opacity" );
m_bandOpacity.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleSliderEditor::uiEditorTypeName() );
@@ -76,6 +78,16 @@ void RimSurfaceIntersectionBand::setSurfaces( RimSurface* surface1, RimSurface*
m_surfaces.push_back( surface1 );
m_surfaces.push_back( surface2 );
updateColorFromSurface();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSurfaceIntersectionBand::setUseCustomColor( bool useCustomColor )
{
m_useCustomColor = useCustomColor;
}
//--------------------------------------------------------------------------------------------------
@@ -115,9 +127,27 @@ RimAnnotationLineAppearance* RimSurfaceIntersectionBand::lineAppearance() const
//--------------------------------------------------------------------------------------------------
cvf::Color3f RimSurfaceIntersectionBand::bandColor() const
{
if ( !m_useCustomColor() )
{
if ( auto surface = surface1() ) return surface->color();
}
return m_bandColor();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::Color3f RimSurfaceIntersectionBand::lineColor() const
{
if ( !m_useCustomColor() )
{
if ( auto surface = surface1() ) return surface->color();
}
return m_lineAppearance->color();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -181,6 +211,12 @@ void RimSurfaceIntersectionBand::fieldChangedByUi( const caf::PdmFieldHandle* ch
m_surfaces.setValue( surfaces );
}
if ( changedField == &m_surfaces || changedField == &m_useCustomColor )
{
updateColorFromSurface();
updateConnectedEditors();
}
onObjectChanged( this );
}
@@ -272,8 +308,16 @@ QString RimSurfaceIntersectionBand::objectName() const
//--------------------------------------------------------------------------------------------------
void RimSurfaceIntersectionBand::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
{
// The colors defined in the Surfaces collection are used unless the user asks for a custom color
updateColorFromSurface();
const bool useCustomColor = m_useCustomColor();
m_bandColor.uiCapability()->setUiReadOnly( !useCustomColor );
m_lineAppearance->setColorReadOnly( !useCustomColor );
{
caf::PdmUiGroup* group = uiOrdering.addNewGroup( "Band Appearance" );
group->add( &m_useCustomColor );
group->add( &m_bandColor );
group->add( &m_bandOpacity );
}
@@ -282,3 +326,26 @@ void RimSurfaceIntersectionBand::defineUiOrdering( QString uiConfigName, caf::Pd
m_lineAppearance->uiOrdering( uiConfigName, *group );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSurfaceIntersectionBand::initAfterRead()
{
updateColorFromSurface();
}
//--------------------------------------------------------------------------------------------------
/// Keep the color fields in sync with the first surface, so the read-only color fields show the
/// colors used to draw the band
//--------------------------------------------------------------------------------------------------
void RimSurfaceIntersectionBand::updateColorFromSurface()
{
if ( m_useCustomColor() ) return;
auto surface = surface1();
if ( !surface ) return;
m_bandColor = surface->color();
m_lineAppearance->setColor( surface->color() );
}
@@ -44,13 +44,17 @@ public:
RimSurfaceIntersectionBand();
void setSurfaces( RimSurface* surface1, RimSurface* surface2 );
void setUseCustomColor( bool useCustomColor );
void setBandColor( const cvf::Color3f& color );
void setBandOpacity( double opacity );
void setPolygonOffsetUnit( double offset );
RimAnnotationLineAppearance* lineAppearance() const;
cvf::Color3f bandColor() const;
float bandOpacity() const;
/// The colors defined in the Surfaces collection are used unless the user has specified a custom color
cvf::Color3f bandColor() const;
cvf::Color3f lineColor() const;
float bandOpacity() const;
double polygonOffsetUnit() const;
@@ -66,12 +70,16 @@ private:
void defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override;
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
void initAfterRead() override;
void onObjectChanged( const caf::SignalEmitter* emitter );
QString objectName() const;
void updateColorFromSurface();
private:
caf::PdmChildField<RimAnnotationLineAppearance*> m_lineAppearance;
caf::PdmField<bool> m_useCustomColor;
caf::PdmField<cvf::Color3f> m_bandColor;
caf::PdmField<double> m_bandOpacity;
caf::PdmField<double> m_bandPolygonOffsetUnit;
@@ -26,6 +26,8 @@
#include "cafPdmUiTreeSelectionEditor.h"
#include <QStringList>
CAF_PDM_SOURCE_INIT( RimSurfaceIntersectionCurve, "RimSurfaceIntersectionCurve" );
//--------------------------------------------------------------------------------------------------
@@ -41,8 +43,11 @@ RimSurfaceIntersectionCurve::RimSurfaceIntersectionCurve()
m_lineAppearance->objectChanged.connect( this, &RimSurfaceIntersectionCurve::onObjectChanged );
uiCapability()->setUiTreeChildrenHidden( true );
CAF_PDM_InitFieldNoDefault( &m_surface1, "Surface1", "Surface 1" );
m_surface1.uiCapability()->setUiEditorTypeName( caf::PdmUiTreeSelectionEditor::uiEditorTypeName() );
CAF_PDM_InitFieldNoDefault( &m_surfaces, "Surfaces", "Surfaces" );
m_surfaces.uiCapability()->setUiEditorTypeName( caf::PdmUiTreeSelectionEditor::uiEditorTypeName() );
m_surfaces.registerKeywordAlias( "Surface1" );
CAF_PDM_InitField( &m_useCustomColor, "UseCustomColor", false, "Custom Color" );
CAF_PDM_InitFieldNoDefault( &m_nameProxy, "NameProxy", "Name" );
m_nameProxy.registerGetMethod( this, &RimSurfaceIntersectionCurve::objectName );
@@ -54,9 +59,9 @@ RimSurfaceIntersectionCurve::RimSurfaceIntersectionCurve()
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimSurface* RimSurfaceIntersectionCurve::surface() const
std::vector<RimSurface*> RimSurfaceIntersectionCurve::surfaces() const
{
return m_surface1();
return m_surfaces.ptrReferencedObjectsByType();
}
//--------------------------------------------------------------------------------------------------
@@ -67,6 +72,16 @@ RimAnnotationLineAppearance* RimSurfaceIntersectionCurve::lineAppearance() const
return m_lineAppearance();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::Color3f RimSurfaceIntersectionCurve::colorForSurface( const RimSurface* surface ) const
{
if ( !m_useCustomColor() && surface ) return surface->color();
return m_lineAppearance->color();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -80,6 +95,12 @@ caf::PdmFieldHandle* RimSurfaceIntersectionCurve::userDescriptionField()
//--------------------------------------------------------------------------------------------------
void RimSurfaceIntersectionCurve::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
{
if ( changedField == &m_surfaces || changedField == &m_useCustomColor )
{
updateColorFromSurface();
updateConnectedEditors();
}
onObjectChanged( this );
}
@@ -90,7 +111,7 @@ QList<caf::PdmOptionItemInfo> RimSurfaceIntersectionCurve::calculateValueOptions
{
QList<caf::PdmOptionItemInfo> options;
if ( fieldNeedingOptions == &m_surface1 )
if ( fieldNeedingOptions == &m_surfaces )
{
RimSurfaceCollection* surfColl = RimTools::surfaceCollection();
@@ -105,10 +126,25 @@ QList<caf::PdmOptionItemInfo> RimSurfaceIntersectionCurve::calculateValueOptions
//--------------------------------------------------------------------------------------------------
void RimSurfaceIntersectionCurve::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
{
uiOrdering.add( &m_surfaces );
caf::PdmUiGroup* group = uiOrdering.addNewGroup( "Line Appearance" );
group->add( &m_useCustomColor );
// The color defined in the Surfaces collection is used unless the user asks for a custom color
updateColorFromSurface();
m_lineAppearance->setColorReadOnly( !m_useCustomColor() );
m_lineAppearance->uiOrdering( uiConfigName, *group );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSurfaceIntersectionCurve::initAfterRead()
{
updateColorFromSurface();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -117,26 +153,45 @@ void RimSurfaceIntersectionCurve::onObjectChanged( const caf::SignalEmitter* emi
objectChanged.send();
}
//--------------------------------------------------------------------------------------------------
/// Keep the color of the line appearance in sync with the first surface, so the read-only color field
/// shows the color used to draw the curve
//--------------------------------------------------------------------------------------------------
void RimSurfaceIntersectionCurve::updateColorFromSurface()
{
if ( m_useCustomColor() ) return;
auto surfaces = m_surfaces.ptrReferencedObjectsByType();
if ( surfaces.empty() || !surfaces.front() ) return;
m_lineAppearance->setColor( surfaces.front()->color() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimSurfaceIntersectionCurve::objectName() const
{
if ( m_surface1() )
auto nameForSurface = []( const RimSurface* surface ) -> QString
{
auto ensembleSurface = m_surface1()->firstAncestorOfType<RimEnsembleSurface>();
auto ensembleSurface = surface->firstAncestorOfType<RimEnsembleSurface>();
if ( ensembleSurface )
{
QString text;
text += ensembleSurface->collectionName();
text += "( " + m_surface1()->fullName() + " )";
return text;
return ensembleSurface->collectionName() + "( " + surface->fullName() + " )";
}
return m_surface1()->fullName();
return surface->fullName();
};
QStringList names;
for ( auto surface : m_surfaces.ptrReferencedObjectsByType() )
{
if ( surface ) names.push_back( nameForSurface( surface ) );
}
return "Surface Curve";
if ( names.isEmpty() ) return "Surface Curve";
return names.join( ", " );
}
//--------------------------------------------------------------------------------------------------
@@ -20,8 +20,9 @@
#include "RimCheckableObject.h"
#include "cafPdmChildField.h"
#include "cafPdmFieldCvfColor.h" // Include to make Pdm work for cvf::Color
#include "cafPdmProxyValueField.h"
#include "cafPdmPtrField.h"
#include "cafPdmPtrArrayField.h"
class RimSurface;
class RimAnnotationLineAppearance;
@@ -42,9 +43,13 @@ public:
public:
RimSurfaceIntersectionCurve();
RimSurface* surface() const;
std::vector<RimSurface*> surfaces() const;
RimAnnotationLineAppearance* lineAppearance() const;
/// The color of the curve for the given surface. The color defined in the Surfaces collection is used unless the
/// user has specified a custom color.
cvf::Color3f colorForSurface( const RimSurface* surface ) const;
static void appendOptionItemsForSources( int currentLevel,
RimSurfaceCollection* currentCollection,
bool showEnsembleSurfaces,
@@ -57,12 +62,16 @@ private:
QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override;
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
void initAfterRead() override;
void onObjectChanged( const caf::SignalEmitter* emitter );
QString objectName() const;
void updateColorFromSurface();
private:
caf::PdmPtrField<RimSurface*> m_surface1;
caf::PdmPtrArrayField<RimSurface*> m_surfaces;
caf::PdmField<bool> m_useCustomColor;
caf::PdmChildField<RimAnnotationLineAppearance*> m_lineAppearance;
caf::PdmProxyValueField<QString> m_nameProxy;
};