mirror of
https://github.com/OPM/ResInsight.git
synced 2025-01-24 15:26:48 -06:00
700 lines
23 KiB
C++
700 lines
23 KiB
C++
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (C) 2018 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 "RiuMohrsCirclePlot.h"
|
|
|
|
#include "RiaColorTables.h"
|
|
|
|
#include "Riu3dSelectionManager.h"
|
|
#include "RiuSummaryQwtPlot.h"
|
|
|
|
#include "RigFemPart.h"
|
|
#include "RigFemPartCollection.h"
|
|
#include "RigFemPartGrid.h"
|
|
#include "RigFemPartResultsCollection.h"
|
|
#include "RigFemResultPosEnum.h"
|
|
#include "RigGeoMechCaseData.h"
|
|
|
|
#include "RimGeoMechCase.h"
|
|
#include "RimGeoMechCellColors.h"
|
|
#include "RimGeoMechResultDefinition.h"
|
|
#include "RimGeoMechView.h"
|
|
|
|
#include "cvfAssert.h"
|
|
|
|
#include <QPainterPath>
|
|
#include <QTimer>
|
|
#include <QWidget>
|
|
#include <qevent.h>
|
|
|
|
#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)
|
|
: QwtPlot(parent)
|
|
, m_sourceGeoMechViewOfLastPlot(nullptr)
|
|
, m_scheduleUpdateAxisScaleTimer(nullptr)
|
|
{
|
|
RiuSummaryQwtPlot::setCommonPlotBehaviour(this);
|
|
|
|
enableAxis(QwtPlot::xBottom, true);
|
|
enableAxis(QwtPlot::yLeft, true);
|
|
enableAxis(QwtPlot::xTop, false);
|
|
enableAxis(QwtPlot::yRight, false);
|
|
|
|
setAxisTitle(QwtPlot::xBottom, "Effective Normal Stress");
|
|
setAxisTitle(QwtPlot::yLeft, "Shear Stress");
|
|
|
|
// The legend will be deleted in the destructor of the plot or when
|
|
// another legend is inserted.
|
|
QwtLegend* legend = new QwtLegend(this);
|
|
this->insertLegend(legend, BottomLegend);
|
|
|
|
// this->setTitle(QString("SE"));
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RiuMohrsCirclePlot::~RiuMohrsCirclePlot()
|
|
{
|
|
deletePlotItems();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuMohrsCirclePlot::appendSelection(const RiuSelectionItem* selectionItem)
|
|
{
|
|
if (this->isVisible())
|
|
{
|
|
m_sourceGeoMechViewOfLastPlot = nullptr;
|
|
|
|
const RiuGeoMechSelectionItem* geoMechSelectionItem = dynamic_cast<const RiuGeoMechSelectionItem*>(selectionItem);
|
|
if (geoMechSelectionItem)
|
|
{
|
|
RimGeoMechView* geoMechView = geoMechSelectionItem->m_view;
|
|
CVF_ASSERT(geoMechView);
|
|
|
|
const size_t gridIndex = geoMechSelectionItem->m_gridIndex;
|
|
const size_t cellIndex = geoMechSelectionItem->m_cellIndex;
|
|
const cvf::Color3f color = geoMechSelectionItem->m_color;
|
|
|
|
queryData(geoMechView, gridIndex, cellIndex, cvf::Color3ub(color));
|
|
updatePlot();
|
|
|
|
m_sourceGeoMechViewOfLastPlot = geoMechView;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
this->clearPlot();
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuMohrsCirclePlot::clearPlot()
|
|
{
|
|
deletePlotItems();
|
|
|
|
m_sourceGeoMechViewOfLastPlot = nullptr;
|
|
|
|
this->replot();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuMohrsCirclePlot::updateOnTimeStepChanged(Rim3dView* changedView)
|
|
{
|
|
if (!this->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
|
|
RimGeoMechView* geoMechView = dynamic_cast<RimGeoMechView*>(changedView);
|
|
if (!geoMechView || geoMechView != m_sourceGeoMechViewOfLastPlot)
|
|
{
|
|
return;
|
|
}
|
|
|
|
std::vector<MohrsCirclesInfo> mohrsCiclesInfosCopy = m_mohrsCiclesInfos;
|
|
deletePlotItems();
|
|
|
|
for (const MohrsCirclesInfo& mohrInfo : mohrsCiclesInfosCopy)
|
|
{
|
|
queryData(mohrInfo.view, mohrInfo.gridIndex, mohrInfo.elmIndex, mohrInfo.color);
|
|
}
|
|
|
|
updatePlot();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QSize RiuMohrsCirclePlot::sizeHint() const
|
|
{
|
|
return QSize(100, 100);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QSize RiuMohrsCirclePlot::minimumSizeHint() const
|
|
{
|
|
return QSize(0, 0);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuMohrsCirclePlot::addMohrCircles(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.elmIndex)
|
|
.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::addEnvelopeCurve(const cvf::Vec3f& principals, RimGeoMechView* view)
|
|
{
|
|
if (!view) return;
|
|
|
|
double cohesion = view->geoMechCase()->cohesion();
|
|
double frictionAngle = view->geoMechCase()->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(view) != m_envolopePlotItems.end())
|
|
{
|
|
if (yVals[1] <= m_envolopePlotItems[view]->maxYValue())
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
m_envolopePlotItems[view]->detach();
|
|
delete m_envolopePlotItems[view];
|
|
m_envolopePlotItems.erase(view);
|
|
}
|
|
}
|
|
|
|
QwtPlotCurve* qwtCurve = new QwtPlotCurve();
|
|
|
|
qwtCurve->setSamples(xVals, yVals, 2);
|
|
|
|
qwtCurve->setStyle(QwtPlotCurve::Lines);
|
|
qwtCurve->setRenderHint(QwtPlotItem::RenderAntialiased, true);
|
|
|
|
const QPen curvePen(envelopeColor(view));
|
|
qwtCurve->setPen(curvePen);
|
|
|
|
qwtCurve->setTitle(QString("<b>Envelope for %1</b>, (<b>S<sub>0</sub></b>: %2, <b>Φ</b>: %3)")
|
|
.arg(view->geoMechCase()->caseUserDescription)
|
|
.arg(cohesion)
|
|
.arg(frictionAngle));
|
|
|
|
qwtCurve->attach(this);
|
|
|
|
m_envolopePlotItems[view] = qwtCurve;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuMohrsCirclePlot::deleteEnvelopes()
|
|
{
|
|
for (const std::pair<RimGeoMechView*, QwtPlotCurve*>& envelope : m_envolopePlotItems)
|
|
{
|
|
envelope.second->detach();
|
|
delete envelope.second;
|
|
}
|
|
|
|
m_envolopePlotItems.clear();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuMohrsCirclePlot::queryData(RimGeoMechView* geoMechView, size_t gridIndex, size_t elmIndex, const cvf::Color3ub& color)
|
|
{
|
|
CVF_ASSERT(geoMechView);
|
|
m_sourceGeoMechViewOfLastPlot = geoMechView;
|
|
|
|
RigFemPart* femPart = geoMechView->femParts()->part(gridIndex);
|
|
if (femPart->elementType(elmIndex) != HEX8P) return;
|
|
|
|
int frameIdx = geoMechView->currentTimeStep();
|
|
RigFemPartResultsCollection* resultCollection = geoMechView->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, frameIdx);
|
|
if (vertexTensors.empty())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
double cohesion = geoMechView->geoMechCase()->cohesion();
|
|
double frictionAngleDeg = geoMechView->geoMechCase()->frictionAngleDeg();
|
|
|
|
size_t i, j, k;
|
|
bool validIndex = femPart->getOrCreateStructGrid()->ijkFromCellIndex(elmIndex, &i, &j, &k);
|
|
|
|
CVF_ASSERT(validIndex);
|
|
if (validIndex)
|
|
{
|
|
MohrsCirclesInfo mohrsCircle(
|
|
principals, gridIndex, elmIndex, i, j, k, geoMechView, calculateFOS(principals, frictionAngleDeg, cohesion), color);
|
|
|
|
addMohrsCirclesInfo(mohrsCircle);
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
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();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuMohrsCirclePlot::addMohrsCirclesInfo(const MohrsCirclesInfo& mohrsCircleInfo)
|
|
{
|
|
m_mohrsCiclesInfos.push_back(mohrsCircleInfo);
|
|
|
|
addEnvelopeCurve(mohrsCircleInfo.principals, mohrsCircleInfo.view);
|
|
addMohrCircles(mohrsCircleInfo);
|
|
updateTransparentCurvesOnPrincipals();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// 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(QwtPlot::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 = RigFemPartResultsCollection::dsm(se1, se3, tanFricAng, cohPrTanFricAngle);
|
|
|
|
return 1.0f / dsm;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QColor RiuMohrsCirclePlot::envelopeColor(RimGeoMechView* view)
|
|
{
|
|
if (m_envolopeColors.find(view) == m_envolopeColors.end())
|
|
{
|
|
cvf::Color3ub cvfColor = RiaColorTables::summaryCurveDefaultPaletteColors().cycledColor3ub(m_envolopeColors.size());
|
|
|
|
QColor color(cvfColor.r(), cvfColor.g(), cvfColor.b());
|
|
|
|
m_envolopeColors[view] = color;
|
|
}
|
|
|
|
return m_envolopeColors[view];
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
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<RimGeoMechView*, 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<RimGeoMechView*, 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 = this->canvas()->height();
|
|
int canvasWidth = this->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;
|
|
}
|
|
|
|
this->setAxisScale(QwtPlot::yLeft, 0, yMaxDisplayed);
|
|
this->setAxisScale(QwtPlot::xBottom, xMin, xMaxDisplayed);
|
|
|
|
this->replot();
|
|
}
|