mirror of
https://github.com/OPM/ResInsight.git
synced 2025-01-01 03:37:15 -06:00
756 lines
26 KiB
C++
756 lines
26 KiB
C++
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (C) 2018- 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 "RiuMohrsCirclePlot.h"
|
|
|
|
#include "RiaColorTables.h"
|
|
#include "RiaLogging.h"
|
|
|
|
#include "RigFemPart.h"
|
|
#include "RigFemPartCollection.h"
|
|
#include "RigFemPartGrid.h"
|
|
#include "RigFemPartResultCalculatorDSM.h"
|
|
#include "RigFemPartResultsCollection.h"
|
|
#include "RigFemResultPosEnum.h"
|
|
#include "RigGeoMechCaseData.h"
|
|
|
|
#include "Rim2dIntersectionView.h"
|
|
#include "RimGeoMechCase.h"
|
|
#include "RimGeoMechCellColors.h"
|
|
#include "RimGeoMechResultDefinition.h"
|
|
#include "RimGeoMechView.h"
|
|
|
|
#include "Riu3dSelectionManager.h"
|
|
#include "RiuQwtPlotTools.h"
|
|
|
|
#include <QPainterPath>
|
|
#include <QPen>
|
|
#include <QTimer>
|
|
#include <QWidget>
|
|
|
|
#include "qwt_legend.h"
|
|
#include "qwt_plot_curve.h"
|
|
#include "qwt_plot_layout.h"
|
|
#include "qwt_plot_rescaler.h"
|
|
#include "qwt_plot_shapeitem.h"
|
|
|
|
#include <cmath>
|
|
|
|
//==================================================================================================
|
|
///
|
|
/// \class RiuMohrsCirclePlot
|
|
///
|
|
///
|
|
///
|
|
//==================================================================================================
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RiuMohrsCirclePlot::RiuMohrsCirclePlot( QWidget* parent )
|
|
: RiuDockedQwtPlot( parent )
|
|
, m_viewToFollowAnimationFrom( nullptr )
|
|
, m_scheduleUpdateAxisScaleTimer( nullptr )
|
|
{
|
|
RiuQwtPlotTools::setCommonPlotBehaviour( this );
|
|
|
|
setAxesCount( QwtAxis::XBottom, 1 );
|
|
setAxesCount( QwtAxis::YLeft, 1 );
|
|
|
|
setAxisTitle( QwtAxis::XBottom, "Effective Normal Stress" );
|
|
setAxisTitle( QwtAxis::YLeft, "Shear Stress" );
|
|
|
|
applyFontSizes( false );
|
|
|
|
// The legend will be deleted in the destructor of the plot or when
|
|
// another legend is inserted.
|
|
QwtLegend* legend = new QwtLegend( this );
|
|
insertLegend( legend, BottomLegend );
|
|
|
|
// setTitle(QString("SE"));
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RiuMohrsCirclePlot::~RiuMohrsCirclePlot()
|
|
{
|
|
deletePlotItems();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuMohrsCirclePlot::appendSelection( const RiuSelectionItem* selectionItem )
|
|
{
|
|
m_viewToFollowAnimationFrom = nullptr;
|
|
|
|
if ( isVisible() )
|
|
{
|
|
Rim3dView* newFollowAnimView = nullptr;
|
|
RiuGeoMechSelectionItem* geoMechSelectionItem = nullptr;
|
|
|
|
geoMechSelectionItem = extractGeoMechSelectionItem( selectionItem, newFollowAnimView );
|
|
|
|
if ( geoMechSelectionItem )
|
|
{
|
|
const size_t gridIndex = geoMechSelectionItem->m_gridIndex;
|
|
RigFemPart* femPart = geoMechSelectionItem->m_resultDefinition->ownerCaseData()->femParts()->part( gridIndex );
|
|
|
|
const size_t cellIndex = geoMechSelectionItem->m_cellIndex;
|
|
const int elmId = femPart->elmId( cellIndex );
|
|
const cvf::Color3f color = geoMechSelectionItem->m_color;
|
|
|
|
addOrUpdateCurves( geoMechSelectionItem->m_resultDefinition,
|
|
geoMechSelectionItem->m_timestepIdx,
|
|
geoMechSelectionItem->m_frameIdx,
|
|
gridIndex,
|
|
cellIndex,
|
|
elmId,
|
|
cvf::Color3ub( color ) );
|
|
|
|
updatePlot();
|
|
|
|
m_viewToFollowAnimationFrom = geoMechSelectionItem->m_view;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
clearPlot();
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuMohrsCirclePlot::clearPlot()
|
|
{
|
|
deletePlotItems();
|
|
|
|
m_viewToFollowAnimationFrom = nullptr;
|
|
|
|
replot();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuMohrsCirclePlot::updateOnTimeStepChanged( Rim3dView* changedView )
|
|
{
|
|
if ( !isVisible() )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Don't update the plot if the view that changed time step is different
|
|
// from the view that was the source of the current plot
|
|
|
|
if ( changedView != m_viewToFollowAnimationFrom )
|
|
{
|
|
return;
|
|
}
|
|
|
|
std::vector<MohrsCirclesInfo> mohrsCiclesInfosCopy = m_mohrsCiclesInfos;
|
|
deletePlotItems();
|
|
|
|
RimGeoMechView* geomechView = dynamic_cast<RimGeoMechView*>( changedView );
|
|
|
|
if ( geomechView == nullptr ) return;
|
|
|
|
auto [stepIdx, frameIdx] = geomechView->currentStepAndDataFrame();
|
|
|
|
for ( const MohrsCirclesInfo& mohrInfo : mohrsCiclesInfosCopy )
|
|
{
|
|
addOrUpdateCurves( mohrInfo.geomResDef, stepIdx, frameIdx, mohrInfo.gridIndex, mohrInfo.elmIndex, mohrInfo.elmId, mohrInfo.color );
|
|
}
|
|
|
|
updatePlot();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QSize RiuMohrsCirclePlot::sizeHint() const
|
|
{
|
|
return QSize( 100, 100 );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QSize RiuMohrsCirclePlot::minimumSizeHint() const
|
|
{
|
|
return QSize( 0, 0 );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuMohrsCirclePlot::addOrUpdateMohrCircleCurves( const MohrsCirclesInfo& mohrsCirclesInfo )
|
|
{
|
|
const cvf::Vec3f& principals = mohrsCirclesInfo.principals;
|
|
|
|
std::array<std::pair<double /*radius*/, double /*centerX*/>, 3> mohrsCircles;
|
|
|
|
mohrsCircles[0].first = ( principals[0] - principals[2] ) / 2.0;
|
|
mohrsCircles[0].second = ( principals[0] + principals[2] ) / 2.0;
|
|
|
|
mohrsCircles[1].first = ( principals[1] - principals[2] ) / 2.0;
|
|
mohrsCircles[1].second = ( principals[1] + principals[2] ) / 2.0;
|
|
|
|
mohrsCircles[2].first = ( principals[0] - principals[1] ) / 2.0;
|
|
mohrsCircles[2].second = ( principals[0] + principals[1] ) / 2.0;
|
|
|
|
for ( size_t i = 0; i < 3; i++ )
|
|
{
|
|
QwtPlotShapeItem* plotItem = new QwtPlotShapeItem( "Circle" );
|
|
|
|
QPainterPath* circleDrawing = new QPainterPath();
|
|
QPointF center( mohrsCircles[i].second, 0 );
|
|
circleDrawing->addEllipse( center, mohrsCircles[i].first, mohrsCircles[i].first );
|
|
|
|
plotItem->setPen( QColor( mohrsCirclesInfo.color.r(), mohrsCirclesInfo.color.g(), mohrsCirclesInfo.color.b() ) );
|
|
plotItem->setShape( *circleDrawing );
|
|
plotItem->setRenderHint( QwtPlotItem::RenderAntialiased, true );
|
|
|
|
if ( i == 0 )
|
|
{
|
|
QString textBuilder;
|
|
textBuilder.append( QString( "<b>FOS</b>: %1, " ).arg( QString::number( mohrsCirclesInfo.factorOfSafety, 'f', 2 ) ) );
|
|
|
|
textBuilder.append( QString( "<b>Element Id</b>: %1, <b>ijk</b>[%2, %3, %4]," )
|
|
.arg( mohrsCirclesInfo.elmId )
|
|
.arg( mohrsCirclesInfo.i )
|
|
.arg( mohrsCirclesInfo.j )
|
|
.arg( mohrsCirclesInfo.k ) );
|
|
|
|
textBuilder.append( QString( "<b>σ<sub>1</sub></b>: %1, " ).arg( principals[0] ) );
|
|
textBuilder.append( QString( "<b>σ<sub>2</sub></b>: %1, " ).arg( principals[1] ) );
|
|
textBuilder.append( QString( "<b>σ<sub>3</sub></b>: %1" ).arg( principals[2] ) );
|
|
|
|
plotItem->setTitle( textBuilder );
|
|
plotItem->setItemAttribute( QwtPlotItem::Legend );
|
|
}
|
|
|
|
plotItem->attach( this );
|
|
|
|
m_circlePlotItems.push_back( plotItem );
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuMohrsCirclePlot::deleteCircles()
|
|
{
|
|
for ( size_t i = 0; i < m_circlePlotItems.size(); i++ )
|
|
{
|
|
m_circlePlotItems[i]->detach();
|
|
delete m_circlePlotItems[i];
|
|
}
|
|
|
|
m_circlePlotItems.clear();
|
|
|
|
for ( size_t i = 0; i < m_transparentCurves.size(); i++ )
|
|
{
|
|
m_transparentCurves[i]->detach();
|
|
delete m_transparentCurves[i];
|
|
}
|
|
|
|
m_transparentCurves.clear();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuMohrsCirclePlot::addorUpdateEnvelopeCurve( const cvf::Vec3f& principals, const RimGeoMechCase* geomCase )
|
|
{
|
|
if ( !geomCase ) return;
|
|
|
|
double cohesion = geomCase->cohesion();
|
|
double frictionAngle = geomCase->frictionAngleDeg();
|
|
|
|
if ( cohesion == HUGE_VAL || frictionAngle == HUGE_VAL || frictionAngle >= 90 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
double xVals[2];
|
|
double yVals[2];
|
|
|
|
double tanFrictionAngle = cvf::Math::abs( cvf::Math::tan( cvf::Math::toRadians( frictionAngle ) ) );
|
|
|
|
if ( tanFrictionAngle == 0 || tanFrictionAngle == HUGE_VAL )
|
|
{
|
|
return;
|
|
}
|
|
|
|
double x = cohesion / tanFrictionAngle;
|
|
|
|
xVals[0] = -x;
|
|
xVals[1] = principals[0];
|
|
|
|
yVals[0] = 0;
|
|
yVals[1] = ( cohesion / x ) * ( x + principals[0] );
|
|
|
|
// If envelope for the view already exists, check if a "larger" envelope should be created
|
|
if ( m_envolopePlotItems.find( geomCase ) != m_envolopePlotItems.end() )
|
|
{
|
|
if ( yVals[1] <= m_envolopePlotItems[geomCase]->maxYValue() )
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
m_envolopePlotItems[geomCase]->detach();
|
|
delete m_envolopePlotItems[geomCase];
|
|
m_envolopePlotItems.erase( geomCase );
|
|
}
|
|
}
|
|
|
|
QwtPlotCurve* qwtCurve = new QwtPlotCurve();
|
|
|
|
qwtCurve->setSamples( xVals, yVals, 2 );
|
|
|
|
qwtCurve->setStyle( QwtPlotCurve::Lines );
|
|
qwtCurve->setRenderHint( QwtPlotItem::RenderAntialiased, true );
|
|
|
|
const QPen curvePen( envelopeColor( geomCase ) );
|
|
qwtCurve->setPen( curvePen );
|
|
|
|
qwtCurve->setTitle( QString( "<b>Envelope for %1</b>, (<b>S<sub>0</sub></b>: %2, <b>Φ</b>: %3)" )
|
|
.arg( geomCase->caseUserDescription() )
|
|
.arg( cohesion )
|
|
.arg( frictionAngle ) );
|
|
|
|
qwtCurve->attach( this );
|
|
|
|
m_envolopePlotItems[geomCase] = qwtCurve;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuMohrsCirclePlot::deleteEnvelopes()
|
|
{
|
|
for ( const std::pair<const RimGeoMechCase* const, QwtPlotCurve*>& envelope : m_envolopePlotItems )
|
|
{
|
|
envelope.second->detach();
|
|
delete envelope.second;
|
|
}
|
|
|
|
m_envolopePlotItems.clear();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RiuMohrsCirclePlot::addOrUpdateCurves( const RimGeoMechResultDefinition* geomResDef,
|
|
int timeStepIndex,
|
|
int frameIndex,
|
|
size_t gridIndex,
|
|
size_t elmIndex,
|
|
int elmId,
|
|
const cvf::Color3ub& color )
|
|
{
|
|
RigFemPart* femPart = geomResDef->ownerCaseData()->femParts()->part( gridIndex );
|
|
|
|
if ( femPart->elementType( elmIndex ) != RigElementType::HEX8P ) return false;
|
|
|
|
RigFemPartResultsCollection* resultCollection = geomResDef->geoMechCase()->geoMechData()->femPartResults();
|
|
|
|
RigFemResultAddress address( RigFemResultPosEnum::RIG_ELEMENT_NODAL, "SE", "" );
|
|
|
|
// TODO: All tensors are calculated every time this function is called. FIX
|
|
|
|
std::vector<caf::Ten3f> vertexTensors = resultCollection->tensors( address, 0, timeStepIndex, frameIndex );
|
|
if ( vertexTensors.empty() )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Calculate average tensor in element
|
|
caf::Ten3f tensorSumOfElmNodes = vertexTensors[femPart->elementNodeResultIdx( (int)elmIndex, 0 )];
|
|
for ( int i = 1; i < 8; i++ )
|
|
{
|
|
tensorSumOfElmNodes = tensorSumOfElmNodes + vertexTensors[femPart->elementNodeResultIdx( (int)elmIndex, i )];
|
|
}
|
|
caf::Ten3f elmTensor = tensorSumOfElmNodes * ( 1.0 / 8.0 );
|
|
|
|
cvf::Vec3f principals = elmTensor.calculatePrincipals( nullptr );
|
|
|
|
if ( !isValidPrincipals( principals ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
double cohesion = geomResDef->geoMechCase()->cohesion();
|
|
double frictionAngleDeg = geomResDef->geoMechCase()->frictionAngleDeg();
|
|
|
|
size_t i, j, k;
|
|
bool validIndex = femPart->getOrCreateStructGrid()->ijkFromCellIndex( elmIndex, &i, &j, &k );
|
|
if ( validIndex )
|
|
{
|
|
int elmId = femPart->elmId( elmIndex );
|
|
|
|
MohrsCirclesInfo
|
|
mohrsCircle( principals, gridIndex, elmIndex, elmId, i, j, k, geomResDef, calculateFOS( principals, frictionAngleDeg, cohesion ), color );
|
|
|
|
m_mohrsCiclesInfos.push_back( mohrsCircle );
|
|
|
|
addorUpdateEnvelopeCurve( mohrsCircle.principals, mohrsCircle.geomResDef->geoMechCase() );
|
|
addOrUpdateMohrCircleCurves( mohrsCircle );
|
|
updateTransparentCurvesOnPrincipals();
|
|
|
|
return true;
|
|
}
|
|
|
|
auto txt = QString( "Not able to create Mohr plot for element index:%1, element ID:%2" ).arg( elmIndex ).arg( elmId );
|
|
RiaLogging::warning( txt );
|
|
|
|
return false;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuMohrsCirclePlot::updatePlot()
|
|
{
|
|
setAxesScaleAndReplot();
|
|
// Update axis scale is called one more time because the legend which is added on a later stage may disrupt the canvas
|
|
scheduleUpdateAxisScale();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Add a transparent curve to make tooltip available on principals crossing the x-axis
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuMohrsCirclePlot::updateTransparentCurvesOnPrincipals()
|
|
{
|
|
for ( size_t i = 0; i < m_transparentCurves.size(); i++ )
|
|
{
|
|
m_transparentCurves[i]->detach();
|
|
delete m_transparentCurves[i];
|
|
}
|
|
|
|
m_transparentCurves.clear();
|
|
|
|
for ( const MohrsCirclesInfo& mohrCircleInfo : m_mohrsCiclesInfos )
|
|
{
|
|
QwtPlotCurve* transparentCurve = new QwtPlotCurve();
|
|
|
|
QVector<QPointF> qVectorPoints;
|
|
|
|
qVectorPoints.push_back( QPointF( mohrCircleInfo.principals[0], 0 ) );
|
|
qVectorPoints.push_back( QPointF( mohrCircleInfo.principals[1], 0 ) );
|
|
qVectorPoints.push_back( QPointF( mohrCircleInfo.principals[2], 0 ) );
|
|
|
|
transparentCurve->setSamples( qVectorPoints );
|
|
transparentCurve->setYAxis( QwtAxis::YLeft );
|
|
transparentCurve->setStyle( QwtPlotCurve::NoCurve );
|
|
transparentCurve->setLegendAttribute( QwtPlotCurve::LegendNoAttribute );
|
|
|
|
transparentCurve->attach( this );
|
|
m_transparentCurves.push_back( transparentCurve );
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
double RiuMohrsCirclePlot::largestCircleRadiusInPlot() const
|
|
{
|
|
double currentLargestDiameter = -HUGE_VAL;
|
|
|
|
for ( const MohrsCirclesInfo& mohrCircleInfo : m_mohrsCiclesInfos )
|
|
{
|
|
if ( mohrCircleInfo.principals[0] > currentLargestDiameter )
|
|
{
|
|
currentLargestDiameter = mohrCircleInfo.principals[0] - mohrCircleInfo.principals[2];
|
|
}
|
|
}
|
|
|
|
return currentLargestDiameter / 2;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
double RiuMohrsCirclePlot::smallestPrincipal() const
|
|
{
|
|
double currentSmallestPrincipal = HUGE_VAL;
|
|
|
|
for ( const MohrsCirclesInfo& mohrCircleInfo : m_mohrsCiclesInfos )
|
|
{
|
|
if ( mohrCircleInfo.principals[2] < currentSmallestPrincipal )
|
|
{
|
|
currentSmallestPrincipal = mohrCircleInfo.principals[2];
|
|
}
|
|
}
|
|
|
|
return currentSmallestPrincipal;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
double RiuMohrsCirclePlot::largestPrincipal() const
|
|
{
|
|
double currentLargestPrincipal = -HUGE_VAL;
|
|
|
|
for ( const MohrsCirclesInfo& mohrCircleInfo : m_mohrsCiclesInfos )
|
|
{
|
|
if ( mohrCircleInfo.principals[0] > currentLargestPrincipal )
|
|
{
|
|
currentLargestPrincipal = mohrCircleInfo.principals[0];
|
|
}
|
|
}
|
|
|
|
return currentLargestPrincipal;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RiuMohrsCirclePlot::isValidPrincipals( const cvf::Vec3f& principals )
|
|
{
|
|
float p1 = principals[0];
|
|
float p2 = principals[1];
|
|
float p3 = principals[2];
|
|
|
|
// Inf
|
|
if ( p1 == HUGE_VAL || p2 == HUGE_VAL || p3 == HUGE_VAL )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Nan
|
|
if ( ( p1 != p1 ) || ( p2 != p2 ) || p3 != p3 )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Principal rules:
|
|
if ( ( p1 < p2 ) || ( p2 < p3 ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
float RiuMohrsCirclePlot::calculateFOS( const cvf::Vec3f& principals, double frictionAngle, double cohesion )
|
|
{
|
|
if ( cvf::Math::cos( frictionAngle ) == 0 )
|
|
{
|
|
return std::nan( "" );
|
|
}
|
|
|
|
float se1 = principals[0];
|
|
float se3 = principals[2];
|
|
|
|
float tanFricAng = cvf::Math::tan( cvf::Math::toRadians( frictionAngle ) );
|
|
float cohPrTanFricAngle = 1.0f * cohesion / tanFricAng;
|
|
|
|
float dsm = RigFemPartResultCalculatorDSM::dsm( se1, se3, tanFricAng, cohPrTanFricAngle );
|
|
|
|
return 1.0f / dsm;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QColor RiuMohrsCirclePlot::envelopeColor( const RimGeoMechCase* geomCase )
|
|
{
|
|
if ( m_envolopeColors.find( geomCase ) == m_envolopeColors.end() )
|
|
{
|
|
cvf::Color3ub cvfColor = RiaColorTables::summaryCurveDefaultPaletteColors().cycledColor3ub( m_envolopeColors.size() );
|
|
|
|
QColor color( cvfColor.r(), cvfColor.g(), cvfColor.b() );
|
|
|
|
m_envolopeColors[geomCase] = color;
|
|
}
|
|
|
|
return m_envolopeColors[geomCase];
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuMohrsCirclePlot::deletePlotItems()
|
|
{
|
|
m_mohrsCiclesInfos.clear();
|
|
|
|
deleteCircles();
|
|
deleteEnvelopes();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuMohrsCirclePlot::scheduleUpdateAxisScale()
|
|
{
|
|
if ( !m_scheduleUpdateAxisScaleTimer )
|
|
{
|
|
m_scheduleUpdateAxisScaleTimer = new QTimer( this );
|
|
connect( m_scheduleUpdateAxisScaleTimer, SIGNAL( timeout() ), this, SLOT( setAxesScaleAndReplot() ) );
|
|
}
|
|
|
|
if ( !m_scheduleUpdateAxisScaleTimer->isActive() )
|
|
{
|
|
m_scheduleUpdateAxisScaleTimer->setSingleShot( true );
|
|
m_scheduleUpdateAxisScaleTimer->start( 100 );
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuMohrsCirclePlot::resizeEvent( QResizeEvent* e )
|
|
{
|
|
setAxesScaleAndReplot();
|
|
|
|
// Update axis scale is called one more time because setAxesScaleAndReplot does not work the first
|
|
// time if the user does a very quick resizing of the window
|
|
scheduleUpdateAxisScale();
|
|
QwtPlot::resizeEvent( e );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuMohrsCirclePlot::idealAxesEndPoints( double* xMin, double* xMax, double* yMax ) const
|
|
{
|
|
*xMin = HUGE_VAL;
|
|
*xMax = -HUGE_VAL;
|
|
*yMax = -HUGE_VAL;
|
|
|
|
double maxYEnvelope = -HUGE_VAL;
|
|
for ( const std::pair<const RimGeoMechCase* const, QwtPlotCurve*>& envelope : m_envolopePlotItems )
|
|
{
|
|
double tempMax = envelope.second->maxYValue();
|
|
if ( tempMax > maxYEnvelope )
|
|
{
|
|
maxYEnvelope = tempMax;
|
|
}
|
|
}
|
|
|
|
*yMax = std::max( maxYEnvelope, 1.2 * largestCircleRadiusInPlot() );
|
|
|
|
double minXEvelope = HUGE_VAL;
|
|
for ( const std::pair<const RimGeoMechCase* const, QwtPlotCurve*>& envelope : m_envolopePlotItems )
|
|
{
|
|
double tempMin = envelope.second->minXValue();
|
|
if ( tempMin < minXEvelope )
|
|
{
|
|
minXEvelope = tempMin;
|
|
}
|
|
}
|
|
|
|
if ( minXEvelope < 0 )
|
|
{
|
|
*xMin = minXEvelope;
|
|
}
|
|
else
|
|
{
|
|
*xMin = 1.1 * smallestPrincipal();
|
|
}
|
|
|
|
*xMax = 1.1 * largestPrincipal();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuMohrsCirclePlot::setAxesScaleAndReplot()
|
|
{
|
|
// yMin is always 0
|
|
double xMin, xMax, yMax;
|
|
idealAxesEndPoints( &xMin, &xMax, &yMax );
|
|
|
|
if ( xMax == -HUGE_VAL || xMin == HUGE_VAL || yMax == -HUGE_VAL )
|
|
{
|
|
return;
|
|
}
|
|
|
|
int canvasHeight = canvas()->height();
|
|
int canvasWidth = canvas()->width();
|
|
|
|
const double minPlotWidth = xMax - xMin;
|
|
const double minPlotHeight = yMax;
|
|
|
|
double xMaxDisplayed = xMax;
|
|
double yMaxDisplayed = yMax;
|
|
|
|
double canvasWidthOverHeightRatio = ( 1.0 * canvasWidth ) / ( 1.0 * canvasHeight );
|
|
|
|
// widthToKeepAspectRatio increases when canvas height is increased
|
|
double widthToKeepAspectRatio = minPlotHeight * canvasWidthOverHeightRatio;
|
|
// heightToKeepAspectRatio increases when canvas width is increased
|
|
double heightToKeepAspectRatio = minPlotWidth / canvasWidthOverHeightRatio;
|
|
|
|
if ( widthToKeepAspectRatio > minPlotWidth )
|
|
{
|
|
xMaxDisplayed = widthToKeepAspectRatio + xMin;
|
|
}
|
|
else if ( heightToKeepAspectRatio > minPlotHeight )
|
|
{
|
|
yMaxDisplayed = heightToKeepAspectRatio;
|
|
}
|
|
|
|
setAxisScale( QwtAxis::YLeft, 0, yMaxDisplayed );
|
|
setAxisScale( QwtAxis::XBottom, xMin, xMaxDisplayed );
|
|
|
|
replot();
|
|
}
|
|
|
|
RiuGeoMechSelectionItem* RiuMohrsCirclePlot::extractGeoMechSelectionItem( const RiuSelectionItem* selectionItem, Rim3dView*& newFollowAnimView )
|
|
{
|
|
newFollowAnimView = nullptr;
|
|
RiuGeoMechSelectionItem* geoMechSelectionItem = nullptr;
|
|
|
|
geoMechSelectionItem = dynamic_cast<RiuGeoMechSelectionItem*>( const_cast<RiuSelectionItem*>( selectionItem ) );
|
|
|
|
if ( geoMechSelectionItem )
|
|
{
|
|
// If we clicked in an geoMech view, and hit something using the standard result definition there,
|
|
// set this up to follow the animation there.
|
|
|
|
RimGeoMechView* clickedInEclView = dynamic_cast<RimGeoMechView*>( geoMechSelectionItem->m_view.p() );
|
|
|
|
if ( clickedInEclView && clickedInEclView->cellResult() == geoMechSelectionItem->m_resultDefinition.p() )
|
|
{
|
|
newFollowAnimView = geoMechSelectionItem->m_view;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
auto intersectionSelItem = dynamic_cast<const Riu2dIntersectionSelectionItem*>( selectionItem );
|
|
|
|
if ( intersectionSelItem && intersectionSelItem->geoMechSelectionItem() )
|
|
{
|
|
geoMechSelectionItem = intersectionSelItem->geoMechSelectionItem();
|
|
newFollowAnimView = intersectionSelItem->view();
|
|
}
|
|
}
|
|
|
|
return geoMechSelectionItem;
|
|
}
|