ResInsight/ApplicationLibCode/ProjectDataModel/RimBoxIntersection.cpp

709 lines
25 KiB
C++

/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2016- Statoil 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 "RimBoxIntersection.h"
#include "Rim3dView.h"
#include "RimCase.h"
#include "RimEclipseView.h"
#include "IntersectionBoxCommands/RicBoxManipulatorEventHandler.h"
#include "RiuViewer.h"
#include "RivBoxIntersectionPartMgr.h"
#include "cafDisplayCoordTransform.h"
#include "cafPdmUiDoubleSliderEditor.h"
#include "cafPdmUiPushButtonEditor.h"
#include "cafPdmUiSliderEditor.h"
namespace caf
{
template <>
void AppEnum<RimBoxIntersection::SinglePlaneState>::setUp()
{
addItem( RimBoxIntersection::PLANE_STATE_NONE, "PLANE_STATE_NONE", "Box" );
addItem( RimBoxIntersection::PLANE_STATE_X, "PLANE_STATE_X", "X Plane" );
addItem( RimBoxIntersection::PLANE_STATE_Y, "PLANE_STATE_Y", "Y Plane" );
addItem( RimBoxIntersection::PLANE_STATE_Z, "PLANE_STATE_Z", "Z Plane" );
setDefault( RimBoxIntersection::PLANE_STATE_NONE );
}
} // namespace caf
CAF_PDM_SOURCE_INIT( RimBoxIntersection, "IntersectionBox" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const RivIntersectionGeometryGeneratorIF* RimBoxIntersection::intersectionGeometryGenerator() const
{
if ( m_intersectionBoxPartMgr.notNull() ) return m_intersectionBoxPartMgr->intersectionGeometryGenerator();
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimBoxIntersection::RimBoxIntersection()
{
CAF_PDM_InitObject( "Intersection Box", ":/IntersectionBox16x16.png", "", "" );
CAF_PDM_InitField( &m_name, "UserDescription", QString( "Intersection Name" ), "Name", "", "", "" );
CAF_PDM_InitField( &m_singlePlaneState,
"singlePlaneState",
caf::AppEnum<SinglePlaneState>( SinglePlaneState::PLANE_STATE_NONE ),
"Box Type",
"",
"",
"" );
CAF_PDM_InitField( &m_minXCoord, "MinXCoord", 0.0, "Min", "", "", "" );
m_minXCoord.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleSliderEditor::uiEditorTypeName() );
CAF_PDM_InitField( &m_maxXCoord, "MaxXCoord", 0.0, "Max", "", "", "" );
m_maxXCoord.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleSliderEditor::uiEditorTypeName() );
CAF_PDM_InitField( &m_minYCoord, "MinYCoord", 0.0, "Min", "", "", "" );
m_minYCoord.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleSliderEditor::uiEditorTypeName() );
CAF_PDM_InitField( &m_maxYCoord, "MaxYCoord", 0.0, "Max", "", "", "" );
m_maxYCoord.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleSliderEditor::uiEditorTypeName() );
CAF_PDM_InitField( &m_minDepth, "MinDepth", 0.0, "Min", "", "", "" );
m_minDepth.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleSliderEditor::uiEditorTypeName() );
CAF_PDM_InitField( &m_maxDepth, "MaxDepth", 0.0, "Max", "", "", "" );
m_maxDepth.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleSliderEditor::uiEditorTypeName() );
CAF_PDM_InitField( &m_xySliderStepSize, "xySliderStepSize", 1.0, "XY Slider Step Size", "", "", "" );
CAF_PDM_InitField( &m_depthSliderStepSize, "DepthSliderStepSize", 0.5, "Depth Slider Step Size", "", "", "" );
CAF_PDM_InitFieldNoDefault( &m_show3DManipulator, "show3DManipulator", "", "", "", "" );
caf::PdmUiPushButtonEditor::configureEditorForField( &m_show3DManipulator );
m_show3DManipulator = false;
setDeletable( true );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimBoxIntersection::~RimBoxIntersection()
{
if ( m_boxManipulator )
{
m_boxManipulator->deleteLater();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
caf::PdmFieldHandle* RimBoxIntersection::userDescriptionField()
{
return &m_name;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimBoxIntersection::name() const
{
return m_name();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimBoxIntersection::setName( const QString& newName )
{
m_name = newName;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::Mat4d RimBoxIntersection::boxOrigin() const
{
cvf::Mat4d mx( cvf::Mat4d::IDENTITY );
mx.setTranslation( cvf::Vec3d( m_minXCoord, m_minYCoord, -m_maxDepth ) );
return mx;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::Vec3d RimBoxIntersection::boxSize() const
{
return cvf::Vec3d( m_maxXCoord, m_maxYCoord, m_maxDepth ) - cvf::Vec3d( m_minXCoord, m_minYCoord, m_minDepth );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimBoxIntersection::setFromOriginAndSize( const cvf::Vec3d& origin, const cvf::Vec3d& size )
{
m_minXCoord = origin.x();
m_minYCoord = origin.y();
m_minDepth = -( origin.z() + size.z() );
m_maxXCoord = origin.x() + size.x();
m_maxYCoord = origin.y() + size.y();
m_maxDepth = -origin.z();
clampSinglePlaneValues();
updateBoxManipulatorGeometry();
updateConnectedEditors();
rebuildGeometryAndScheduleCreateDisplayModel();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimBoxIntersection::show3dManipulator() const
{
return m_show3DManipulator;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimBoxIntersection::SinglePlaneState RimBoxIntersection::singlePlaneState() const
{
return m_singlePlaneState();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimBoxIntersection::setToDefaultSizeBox()
{
cvf::BoundingBox boundingBox = currentCellBoundingBox();
cvf::Vec3d center = boundingBox.center();
double defaultWidthFactor = 0.5;
m_minXCoord = center.x() - 0.5 * boundingBox.extent().x() * defaultWidthFactor;
m_minYCoord = center.y() - 0.5 * boundingBox.extent().y() * defaultWidthFactor;
m_minDepth = -( center.z() + 0.5 * boundingBox.extent().z() * defaultWidthFactor );
m_maxXCoord = center.x() + 0.5 * boundingBox.extent().x() * defaultWidthFactor;
m_maxYCoord = center.y() + 0.5 * boundingBox.extent().y() * defaultWidthFactor;
m_maxDepth = -( center.z() - 0.5 * boundingBox.extent().z() * defaultWidthFactor );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimBoxIntersection::setToDefaultSizeSlice( SinglePlaneState plane, const cvf::Vec3d& position )
{
m_singlePlaneState = plane;
cvf::BoundingBox boundingBox = currentCellBoundingBox();
cvf::Vec3d center = position;
if ( center.isUndefined() ) center = boundingBox.center();
double defaultWidthFactor = 0.5;
m_minXCoord = center[0] - 0.5 * boundingBox.extent().x() * defaultWidthFactor;
m_minYCoord = center[1] - 0.5 * boundingBox.extent().y() * defaultWidthFactor;
m_minDepth = -( center[2] + 0.5 * boundingBox.extent().z() * defaultWidthFactor );
m_maxXCoord = center[0] + 0.5 * boundingBox.extent().x() * defaultWidthFactor;
m_maxYCoord = center[1] + 0.5 * boundingBox.extent().y() * defaultWidthFactor;
m_maxDepth = -( center[2] - 0.5 * boundingBox.extent().z() * defaultWidthFactor );
switch ( plane )
{
case PLANE_STATE_X:
m_minXCoord = m_maxXCoord = center[0];
break;
case PLANE_STATE_Y:
m_minYCoord = m_maxYCoord = center[1];
break;
case PLANE_STATE_Z:
m_minDepth = m_maxDepth = -center[2];
break;
}
updateVisibility();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RivBoxIntersectionPartMgr* RimBoxIntersection::intersectionBoxPartMgr()
{
if ( m_intersectionBoxPartMgr.isNull() ) m_intersectionBoxPartMgr = new RivBoxIntersectionPartMgr( this );
return m_intersectionBoxPartMgr.p();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimBoxIntersection::appendManipulatorPartsToModel( cvf::ModelBasicList* model )
{
if ( show3dManipulator() && m_boxManipulator )
{
m_boxManipulator->appendPartsToModel( model );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimBoxIntersection::rebuildGeometry()
{
m_intersectionBoxPartMgr = nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimBoxIntersection::fieldChangedByUi( const caf::PdmFieldHandle* changedField,
const QVariant& oldValue,
const QVariant& newValue )
{
if ( changedField == &m_singlePlaneState )
{
switchSingelPlaneState();
updateVisibility();
updateBoxManipulatorGeometry();
}
else if ( changedField == &m_minXCoord )
{
if ( m_singlePlaneState == PLANE_STATE_X )
{
m_maxXCoord = m_minXCoord;
}
else
{
m_minXCoord = std::min( m_maxXCoord, m_minXCoord );
}
}
else if ( changedField == &m_minYCoord )
{
if ( m_singlePlaneState == PLANE_STATE_Y )
{
m_maxYCoord = m_minYCoord;
}
else
{
m_minYCoord = std::min( m_maxYCoord, m_minYCoord );
}
}
else if ( changedField == &m_minDepth )
{
if ( m_singlePlaneState == PLANE_STATE_Z )
{
m_maxDepth = m_minDepth;
}
else
{
m_minDepth = std::min( m_maxDepth, m_minDepth );
}
}
else if ( changedField == &m_maxXCoord )
{
m_maxXCoord = std::max( m_maxXCoord, m_minXCoord );
}
else if ( changedField == &m_maxYCoord )
{
m_maxYCoord = std::max( m_maxYCoord, m_minYCoord );
}
else if ( changedField == &m_maxDepth )
{
m_maxDepth = std::max( m_maxDepth, m_minDepth );
}
else if ( changedField == &m_show3DManipulator )
{
if ( m_show3DManipulator )
{
if ( viewer() )
{
m_boxManipulator = new RicBoxManipulatorEventHandler( viewer() );
Rim3dView* rimView = nullptr;
this->firstAncestorOrThisOfType( rimView );
for ( Rim3dView* mainView : rimView->viewsUsingThisAsComparisonView() )
{
m_boxManipulator->registerInAdditionalViewer( mainView->viewer() );
}
connect( m_boxManipulator, SIGNAL( notifyRedraw() ), this, SLOT( slotScheduleRedraw() ) );
connect( m_boxManipulator,
SIGNAL( notifyUpdate( const cvf::Vec3d&, const cvf::Vec3d& ) ),
this,
SLOT( slotUpdateGeometry( const cvf::Vec3d&, const cvf::Vec3d& ) ) );
updateBoxManipulatorGeometry();
}
}
else
{
if ( m_boxManipulator )
{
m_boxManipulator->deleteLater();
m_boxManipulator = nullptr;
}
}
}
if ( changedField == &m_minXCoord || changedField == &m_minYCoord || changedField == &m_minDepth ||
changedField == &m_maxXCoord || changedField == &m_maxYCoord || changedField == &m_maxDepth )
{
if ( m_boxManipulator )
{
Rim3dView* rimView = nullptr;
this->firstAncestorOrThisOfType( rimView );
if ( rimView )
{
cvf::ref<caf::DisplayCoordTransform> transForm = rimView->displayCoordTransform();
m_boxManipulator->setOrigin( transForm->transformToDisplayCoord( boxOrigin().translation() ) );
m_boxManipulator->setSize( transForm->scaleToDisplaySize( boxSize() ) );
}
}
}
if ( changedField != &m_name )
{
rebuildGeometryAndScheduleCreateDisplayModel();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimBoxIntersection::updateBoxManipulatorGeometry()
{
if ( m_boxManipulator.isNull() ) return;
Rim3dView* rimView = nullptr;
this->firstAncestorOrThisOfType( rimView );
if ( !rimView ) return;
cvf::ref<caf::DisplayCoordTransform> transForm = rimView->displayCoordTransform();
m_boxManipulator->setOrigin( transForm->transformToDisplayCoord( boxOrigin().translation() ) );
m_boxManipulator->setSize( transForm->scaleToDisplaySize( boxSize() ) );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimBoxIntersection::defineEditorAttribute( const caf::PdmFieldHandle* field,
QString uiConfigName,
caf::PdmUiEditorAttribute* attribute )
{
caf::PdmUiDoubleSliderEditorAttribute* myAttr = dynamic_cast<caf::PdmUiDoubleSliderEditorAttribute*>( attribute );
if ( myAttr )
{
cvf::BoundingBox cellsBoundingBox = currentCellBoundingBox();
if ( field == &m_minXCoord || field == &m_maxXCoord )
{
myAttr->m_minimum = cellsBoundingBox.min().x();
myAttr->m_maximum = cellsBoundingBox.max().x();
int range = cellsBoundingBox.extent().x();
int tickCount = range / m_xySliderStepSize;
myAttr->m_sliderTickCount = cvf::Math::abs( tickCount );
}
else if ( field == &m_minYCoord || field == &m_maxYCoord )
{
myAttr->m_minimum = cellsBoundingBox.min().y();
myAttr->m_maximum = cellsBoundingBox.max().y();
int range = cellsBoundingBox.extent().y();
int tickCount = range / m_xySliderStepSize;
myAttr->m_sliderTickCount = cvf::Math::abs( tickCount );
}
else if ( field == &m_minDepth || field == &m_maxDepth )
{
myAttr->m_minimum = -cellsBoundingBox.max().z();
myAttr->m_maximum = -cellsBoundingBox.min().z();
int range = cellsBoundingBox.extent().z();
int tickCount = range / m_depthSliderStepSize;
myAttr->m_sliderTickCount = cvf::Math::abs( tickCount );
}
}
if ( field == &m_show3DManipulator )
{
caf::PdmUiPushButtonEditorAttribute* attrib = dynamic_cast<caf::PdmUiPushButtonEditorAttribute*>( attribute );
if ( attrib )
{
if ( m_show3DManipulator )
{
attrib->m_buttonText = "Hide 3D manipulator";
}
else
{
attrib->m_buttonText = "Show 3D manipulator";
}
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimBoxIntersection::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
{
uiOrdering.add( &m_name );
{
caf::PdmUiGroup* group = uiOrdering.addNewGroup( "Options" );
group->add( &m_singlePlaneState );
group->add( &m_showInactiveCells );
}
cvf::BoundingBox cellsBoundingBox = currentCellBoundingBox();
{
caf::PdmUiGroup* group = uiOrdering.addNewGroup(
"X Coordinates " + QString( " [%1 %2]" ).arg( cellsBoundingBox.min().x() ).arg( cellsBoundingBox.max().x() ) );
group->add( &m_minXCoord );
group->add( &m_maxXCoord );
}
{
caf::PdmUiGroup* group = uiOrdering.addNewGroup(
"Y Coordinates" + QString( " [%1 %2]" ).arg( cellsBoundingBox.min().y() ).arg( cellsBoundingBox.max().y() ) );
group->add( &m_minYCoord );
group->add( &m_maxYCoord );
}
{
caf::PdmUiGroup* group = uiOrdering.addNewGroup(
"Depth" + QString( " [%1 %2]" ).arg( -cellsBoundingBox.max().z() ).arg( -cellsBoundingBox.min().z() ) );
group->add( &m_minDepth );
group->add( &m_maxDepth );
}
{
caf::PdmUiGroup* group = uiOrdering.addNewGroup( "Slider Options" );
group->add( &m_xySliderStepSize );
group->add( &m_depthSliderStepSize );
}
uiOrdering.add( &m_show3DManipulator );
this->defineSeparateDataSourceUi( uiConfigName, uiOrdering );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimBoxIntersection::initAfterRead()
{
RimIntersection::initAfterRead();
updateVisibility();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimBoxIntersection::slotScheduleRedraw()
{
Rim3dView* rimView = nullptr;
this->firstAncestorOrThisOfType( rimView );
if ( rimView )
{
rimView->scheduleCreateDisplayModelAndRedraw();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimBoxIntersection::slotUpdateGeometry( const cvf::Vec3d& origin, const cvf::Vec3d& size )
{
Rim3dView* rimView = nullptr;
this->firstAncestorOrThisOfType( rimView );
if ( rimView )
{
cvf::ref<caf::DisplayCoordTransform> transForm = rimView->displayCoordTransform();
cvf::Vec3d domainOrigin = transForm->transformToDomainCoord( origin );
cvf::Vec3d domainSize = transForm->scaleToDomainSize( size );
setFromOriginAndSize( domainOrigin, domainSize );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimBoxIntersection::rebuildGeometryAndScheduleCreateDisplayModel()
{
m_intersectionBoxPartMgr = nullptr;
slotScheduleRedraw();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimBoxIntersection::updateVisibility()
{
m_maxXCoord.uiCapability()->setUiReadOnly( false );
m_maxYCoord.uiCapability()->setUiReadOnly( false );
m_maxDepth.uiCapability()->setUiReadOnly( false );
if ( m_singlePlaneState == PLANE_STATE_X )
{
m_maxXCoord.uiCapability()->setUiReadOnly( true );
this->setUiIconFromResourceString( QString( ":/IntersectionXPlane16x16.png" ) );
}
else if ( m_singlePlaneState == PLANE_STATE_Y )
{
m_maxYCoord.uiCapability()->setUiReadOnly( true );
this->setUiIconFromResourceString( QString( ":/IntersectionYPlane16x16.png" ) );
}
else if ( m_singlePlaneState == PLANE_STATE_Z )
{
m_maxDepth.uiCapability()->setUiReadOnly( true );
this->setUiIconFromResourceString( QString( ":/IntersectionZPlane16x16.png" ) );
}
else
{
this->setUiIconFromResourceString( QString( ":/IntersectionBox16x16.png" ) );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimBoxIntersection::clampSinglePlaneValues()
{
if ( m_singlePlaneState == PLANE_STATE_X )
{
m_maxXCoord = m_minXCoord = 0.5 * ( m_minXCoord + m_maxXCoord );
}
else if ( m_singlePlaneState == PLANE_STATE_Y )
{
m_maxYCoord = m_minYCoord = 0.5 * ( m_minYCoord + m_maxYCoord );
}
else if ( m_singlePlaneState == PLANE_STATE_Z )
{
m_maxDepth = m_minDepth = 0.5 * ( m_minDepth + m_maxDepth );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimBoxIntersection::switchSingelPlaneState()
{
cvf::Vec3d orgSize = boxSize();
double orgWidth = orgSize.length();
switch ( m_singlePlaneState() ) // New collapsed direction
{
case PLANE_STATE_X:
orgWidth = orgSize[0];
break;
case PLANE_STATE_Y:
orgWidth = orgSize[1];
break;
case PLANE_STATE_Z:
orgWidth = orgSize[2];
break;
case PLANE_STATE_NONE:
orgWidth = orgSize.length() * 0.3;
break;
}
// For the originally collapsed direction, set a new width
if ( m_minXCoord() == m_maxXCoord() )
{
double center = m_minXCoord;
m_minXCoord = center - 0.5 * orgWidth;
m_maxXCoord = center + 0.5 * orgWidth;
}
if ( m_minYCoord() == m_maxYCoord() )
{
double center = m_minYCoord;
m_minYCoord = center - 0.5 * orgWidth;
m_maxYCoord = center + 0.5 * orgWidth;
}
if ( m_minDepth() == m_maxDepth() )
{
double center = m_minDepth;
m_minDepth = center - 0.5 * orgWidth;
m_maxDepth = center + 0.5 * orgWidth;
}
clampSinglePlaneValues();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::BoundingBox RimBoxIntersection::currentCellBoundingBox()
{
RimCase* rimCase = nullptr;
this->firstAncestorOrThisOfType( rimCase );
CVF_ASSERT( rimCase );
/*
RimEclipseView* eclView = nullptr;
this->firstAncestorOrThisOfType(eclView);
bool useAllCells = true;
if (eclView)
{
useAllCells = eclView->showInactiveCells();
}
if(false)//useAllCells) // For now, only use the active CellsBBox.
return rimCase->allCellsBoundingBox();
else */
return rimCase->activeCellsBoundingBox();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiuViewer* RimBoxIntersection::viewer()
{
Rim3dView* rimView = nullptr;
this->firstAncestorOrThisOfType( rimView );
RiuViewer* riuViewer = nullptr;
if ( rimView ) riuViewer = rimView->viewer();
return riuViewer;
}