#2540 Mohr circle: Improve scaling of window

This commit is contained in:
Rebecca Cox 2018-03-05 11:59:46 +01:00
parent 5e54c58c6d
commit fcf8bf6e68
2 changed files with 190 additions and 106 deletions

View File

@ -38,7 +38,9 @@
#include "cvfAssert.h" #include "cvfAssert.h"
#include <QPainterPath> #include <QPainterPath>
#include <QTimer>
#include <QWidget> #include <QWidget>
#include <qevent.h>
#include "qwt_legend.h" #include "qwt_legend.h"
#include "qwt_plot_curve.h" #include "qwt_plot_curve.h"
@ -60,16 +62,12 @@
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
RiuMohrsCirclePlot::RiuMohrsCirclePlot(QWidget* parent) RiuMohrsCirclePlot::RiuMohrsCirclePlot(QWidget* parent)
: QwtPlot(parent), m_sourceGeoMechViewOfLastPlot(nullptr) : QwtPlot(parent)
, m_sourceGeoMechViewOfLastPlot(nullptr)
, m_scheduleUpdateAxisScaleTimer(nullptr)
{ {
RiuSummaryQwtPlot::setCommonPlotBehaviour(this); RiuSummaryQwtPlot::setCommonPlotBehaviour(this);
m_rescaler = new QwtPlotRescaler(this->canvas());
m_rescaler->setReferenceAxis(QwtPlot::yLeft);
m_rescaler->setAspectRatio(QwtPlot::xBottom, 1.0);
m_rescaler->setRescalePolicy(QwtPlotRescaler::Fixed);
m_rescaler->setEnabled(true);
enableAxis(QwtPlot::xBottom, true); enableAxis(QwtPlot::xBottom, true);
enableAxis(QwtPlot::yLeft, true); enableAxis(QwtPlot::yLeft, true);
enableAxis(QwtPlot::xTop, false); enableAxis(QwtPlot::xTop, false);
@ -92,11 +90,6 @@ RiuMohrsCirclePlot::RiuMohrsCirclePlot(QWidget* parent)
RiuMohrsCirclePlot::~RiuMohrsCirclePlot() RiuMohrsCirclePlot::~RiuMohrsCirclePlot()
{ {
deletePlotItems(); deletePlotItems();
if (m_rescaler)
{
delete m_rescaler;
}
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -105,9 +98,9 @@ RiuMohrsCirclePlot::~RiuMohrsCirclePlot()
void RiuMohrsCirclePlot::updateOnSelectionChanged(const RiuSelectionItem* selectionItem) void RiuMohrsCirclePlot::updateOnSelectionChanged(const RiuSelectionItem* selectionItem)
{ {
const RiuGeoMechSelectionItem* geoMechSelectionItem = dynamic_cast<const RiuGeoMechSelectionItem*>(selectionItem); const RiuGeoMechSelectionItem* geoMechSelectionItem = dynamic_cast<const RiuGeoMechSelectionItem*>(selectionItem);
m_sourceGeoMechViewOfLastPlot = nullptr; m_sourceGeoMechViewOfLastPlot = nullptr;
if (!geoMechSelectionItem) if (!geoMechSelectionItem)
{ {
this->clearPlot(); this->clearPlot();
@ -124,7 +117,7 @@ void RiuMohrsCirclePlot::updateOnSelectionChanged(const RiuSelectionItem* select
const cvf::Color3f color = geoMechSelectionItem->m_color; const cvf::Color3f color = geoMechSelectionItem->m_color;
queryDataAndUpdatePlot(geoMechView, gridIndex, cellIndex, cvf::Color3ub(color)); queryDataAndUpdatePlot(geoMechView, gridIndex, cellIndex, cvf::Color3ub(color));
m_sourceGeoMechViewOfLastPlot = geoMechView; m_sourceGeoMechViewOfLastPlot = geoMechView;
} }
else else
@ -144,7 +137,7 @@ void RiuMohrsCirclePlot::clearPlot()
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
void RiuMohrsCirclePlot::updateOnTimeStepChanged(Rim3dView* changedView) void RiuMohrsCirclePlot::updateOnTimeStepChanged(Rim3dView* changedView)
{ {
@ -161,12 +154,13 @@ void RiuMohrsCirclePlot::updateOnTimeStepChanged(Rim3dView* changedView)
} }
// Fetch the current global selection and only continue if the selection's view matches the view with time step change // Fetch the current global selection and only continue if the selection's view matches the view with time step change
const RiuGeoMechSelectionItem* geoMechSelectionItem = dynamic_cast<const RiuGeoMechSelectionItem*>(RiuSelectionManager::instance()->selectedItem()); const RiuGeoMechSelectionItem* geoMechSelectionItem =
dynamic_cast<const RiuGeoMechSelectionItem*>(RiuSelectionManager::instance()->selectedItem());
if (geoMechSelectionItem && geoMechSelectionItem->m_view == geoMechView) if (geoMechSelectionItem && geoMechSelectionItem->m_view == geoMechView)
{ {
const size_t gridIndex = geoMechSelectionItem->m_gridIndex; const size_t gridIndex = geoMechSelectionItem->m_gridIndex;
const size_t gridCellIndex = geoMechSelectionItem->m_cellIndex; const size_t gridCellIndex = geoMechSelectionItem->m_cellIndex;
const cvf::Color3f color = geoMechSelectionItem->m_color; const cvf::Color3f color = geoMechSelectionItem->m_color;
deletePlotItems(); deletePlotItems();
@ -277,7 +271,7 @@ void RiuMohrsCirclePlot::addEnvelope(const cvf::Vec3f& principals, RimGeoMechVie
double cohesion = view->geoMechCase()->cohesion(); double cohesion = view->geoMechCase()->cohesion();
double frictionAngle = view->geoMechCase()->frictionAngleDeg(); double frictionAngle = view->geoMechCase()->frictionAngleDeg();
if (cohesion == HUGE_VAL || frictionAngle == HUGE_VAL) if (cohesion == HUGE_VAL || frictionAngle == HUGE_VAL || frictionAngle >= 90)
{ {
return; return;
} }
@ -292,24 +286,13 @@ void RiuMohrsCirclePlot::addEnvelope(const cvf::Vec3f& principals, RimGeoMechVie
return; return;
} }
yVals[0] = 0;
double x = cohesion / tanFrictionAngle; double x = cohesion / tanFrictionAngle;
if (principals[0] < 0)
{
xVals[0] = x;
xVals[1] = principals[2];
yVals[1] = (cohesion / x) * (x + principals[2]); xVals[0] = -x;
} xVals[1] = principals[0];
else
{
xVals[0] = -x;
xVals[1] = principals[0];
yVals[1] = (cohesion / x) * (x + 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 envelope for the view already exists, check if a "larger" envelope should be created
if (m_envolopePlotItems.find(view) != m_envolopePlotItems.end()) if (m_envolopePlotItems.find(view) != m_envolopePlotItems.end())
@ -401,23 +384,19 @@ void RiuMohrsCirclePlot::queryDataAndUpdatePlot(RimGeoMechView* geoMechView
return; return;
} }
double cohesion = geoMechView->geoMechCase()->cohesion(); double cohesion = geoMechView->geoMechCase()->cohesion();
double frictionAngleDeg = geoMechView->geoMechCase()->frictionAngleDeg(); double frictionAngleDeg = geoMechView->geoMechCase()->frictionAngleDeg();
size_t i, j, k; size_t i, j, k;
femPart->structGrid()->ijkFromCellIndex(elmIndex, &i, &j, &k); femPart->structGrid()->ijkFromCellIndex(elmIndex, &i, &j, &k);
MohrsCirclesInfo mohrsCircle; MohrsCirclesInfo mohrsCircle(principals, elmIndex, i, j, k, calculateFOS(principals, frictionAngleDeg, cohesion), color);
mohrsCircle.color = color;
mohrsCircle.elmIndex = elmIndex;
mohrsCircle.factorOfSafety = calculateFOS(principals, frictionAngleDeg, cohesion);
mohrsCircle.principals = principals;
mohrsCircle.i = i;
mohrsCircle.j = j;
mohrsCircle.k = k;
addMohrsCirclesInfo(mohrsCircle, geoMechView); addMohrsCirclesInfo(mohrsCircle, geoMechView);
replotAndScaleAxis();
setAxesScaleAndReplot();
// Update axis scale is called one more time because the legend which is added on a later stage may disrupt the canvas
scheduleUpdateAxisScale();
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -429,6 +408,7 @@ void RiuMohrsCirclePlot::addMohrsCirclesInfo(const MohrsCirclesInfo& mohrsCircle
addEnvelope(mohrsCircleInfo.principals, view); addEnvelope(mohrsCircleInfo.principals, view);
addMohrCircles(mohrsCircleInfo); addMohrCircles(mohrsCircleInfo);
updateTransparentCurvesOnPrincipals();
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -503,53 +483,19 @@ double RiuMohrsCirclePlot::smallestPrincipal() const
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
void RiuMohrsCirclePlot::replotAndScaleAxis() double RiuMohrsCirclePlot::largestPrincipal() const
{ {
double maxYEnvelope = -HUGE_VAL; double currentLargestPrincipal = -HUGE_VAL;
for (const std::pair<RimGeoMechView*, QwtPlotCurve*>& envelope : m_envolopePlotItems) for (const MohrsCirclesInfo& mohrCircleInfo : m_mohrsCiclesInfos)
{ {
double tempMax = envelope.second->maxYValue(); if (mohrCircleInfo.principals[0] > currentLargestPrincipal)
if (tempMax > maxYEnvelope)
{ {
maxYEnvelope = tempMax; currentLargestPrincipal = mohrCircleInfo.principals[0];
} }
} }
double yHeight = std::max(maxYEnvelope, 1.2 * largestCircleRadiusInPlot()); return currentLargestPrincipal;
this->setAxisScale(QwtPlot::yLeft, 0, yHeight);
double minXEvelope = HUGE_VAL;
for (const std::pair<RimGeoMechView*, QwtPlotCurve*>& envelope : m_envolopePlotItems)
{
double tempMin = envelope.second->minXValue();
if (tempMin < minXEvelope)
{
minXEvelope = tempMin;
}
}
double xMin;
if (minXEvelope < 0)
{
xMin = minXEvelope;
}
else
{
xMin = 1.1 * smallestPrincipal();
}
// When using the rescaler, xMax is ignored
this->setAxisScale(QwtPlot::xBottom, xMin, 0);
updateTransparentCurvesOnPrincipals();
//Replotting must be done before rescaling
this->replot();
m_rescaler->rescale();
this->plotLayout()->setAlignCanvasToScales(true);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -592,10 +538,10 @@ float RiuMohrsCirclePlot::calculateFOS(const cvf::Vec3f& principals, double fric
if (cvf::Math::cos(frictionAngle) == 0) if (cvf::Math::cos(frictionAngle) == 0)
{ {
return 0; return 0.0f;
} }
float tanFricAng = cvf::Math::tan(cvf::Math::toRadians(frictionAngle)); float tanFricAng = cvf::Math::tan(cvf::Math::toRadians(frictionAngle));
float cohPrTanFricAngle = 1.0f * cohesion / tanFricAng; float cohPrTanFricAngle = 1.0f * cohesion / tanFricAng;
float pi_4 = 0.785398163397448309616f; float pi_4 = 0.785398163397448309616f;
@ -622,7 +568,7 @@ QColor RiuMohrsCirclePlot::envelopeColor(RimGeoMechView* view)
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
void RiuMohrsCirclePlot::deletePlotItems() void RiuMohrsCirclePlot::deletePlotItems()
{ {
@ -632,3 +578,121 @@ void RiuMohrsCirclePlot::deletePlotItems()
deleteEnvelopes(); 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();
}

View File

@ -19,8 +19,8 @@
#pragma once #pragma once
#include "qwt_plot.h" #include "qwt_plot.h"
#include "qwt_plot_item.h"
#include "qwt_plot_curve.h" #include "qwt_plot_curve.h"
#include "qwt_plot_item.h"
#include "cafTensor3.h" #include "cafTensor3.h"
@ -28,14 +28,11 @@
#include <array> #include <array>
class QTimer;
class QWidget; class QWidget;
class QwtPlotRescaler;
class QwtPlotTextLabel;
class QwtRoundScaleDraw;
class RimGeoMechView;
class RiuSelectionItem;
class Rim3dView; class Rim3dView;
class RimGeoMechView; class RimGeoMechView;
class RiuSelectionItem;
//================================================================================================== //==================================================================================================
// //
@ -58,16 +55,34 @@ public:
public: public:
struct MohrsCirclesInfo struct MohrsCirclesInfo
{ {
cvf::Vec3f principals; MohrsCirclesInfo(cvf::Vec3f principals,
size_t elmIndex; size_t elmIndex,
size_t i, j, k; size_t i,
double factorOfSafety; size_t j,
size_t k,
double factorOfSafety,
cvf::Color3ub color)
: principals(principals)
, elmIndex(elmIndex)
, i(i)
, j(j)
, k(k)
, factorOfSafety(factorOfSafety)
, color(color) {}
cvf::Vec3f principals;
size_t elmIndex;
size_t i, j, k;
double factorOfSafety;
cvf::Color3ub color; cvf::Color3ub color;
}; };
private: private:
virtual QSize sizeHint() const override; virtual QSize sizeHint() const override;
virtual QSize minimumSizeHint() const override; virtual QSize minimumSizeHint() const override;
virtual void resizeEvent(QResizeEvent* e) override;
void idealAxesEndPoints(double* xMin, double* xMax, double* yMax) const;
void addMohrCircles(const MohrsCirclesInfo& mohrsCirclesInfo); void addMohrCircles(const MohrsCirclesInfo& mohrsCirclesInfo);
void deleteCircles(); void deleteCircles();
@ -76,27 +91,32 @@ private:
void deleteEnvelopes(); void deleteEnvelopes();
void queryDataAndUpdatePlot(RimGeoMechView* geoMechView, size_t gridIndex, size_t elmIndex, const cvf::Color3ub& color); void queryDataAndUpdatePlot(RimGeoMechView* geoMechView, size_t gridIndex, size_t elmIndex, const cvf::Color3ub& color);
void addMohrsCirclesInfo(const MohrsCirclesInfo& mohrsCircleInfo, RimGeoMechView* view); void addMohrsCirclesInfo(const MohrsCirclesInfo& mohrsCircleInfo, RimGeoMechView* view);
void updateTransparentCurvesOnPrincipals(); void updateTransparentCurvesOnPrincipals();
double largestCircleRadiusInPlot() const; double largestCircleRadiusInPlot() const;
double smallestPrincipal() const; double smallestPrincipal() const;
double largestPrincipal() const;
void replotAndScaleAxis();
static bool isValidPrincipals(const cvf::Vec3f& principals); static bool isValidPrincipals(const cvf::Vec3f& principals);
static float calculateFOS(const cvf::Vec3f& principals, double frictionAngle, double cohesion); static float calculateFOS(const cvf::Vec3f& principals, double frictionAngle, double cohesion);
QColor envelopeColor(RimGeoMechView* view); QColor envelopeColor(RimGeoMechView* view);
void deletePlotItems(); void deletePlotItems();
void scheduleUpdateAxisScale();
private slots:
void setAxesScaleAndReplot();
private: private:
std::vector<QwtPlotItem*> m_circlePlotItems; std::vector<QwtPlotItem*> m_circlePlotItems;
std::vector<QwtPlotCurve*> m_transparentCurves; std::vector<QwtPlotCurve*> m_transparentCurves;
std::map<RimGeoMechView*, QwtPlotCurve*> m_envolopePlotItems; std::map<RimGeoMechView*, QwtPlotCurve*> m_envolopePlotItems;
std::map<RimGeoMechView*, QColor> m_envolopeColors; std::map<RimGeoMechView*, QColor> m_envolopeColors;
@ -104,5 +124,5 @@ private:
RimGeoMechView* m_sourceGeoMechViewOfLastPlot; RimGeoMechView* m_sourceGeoMechViewOfLastPlot;
QwtPlotRescaler* m_rescaler; QTimer* m_scheduleUpdateAxisScaleTimer;
}; };