Files

269 lines
11 KiB
C++
Raw Permalink Normal View History

2024-05-03 09:54:34 +02:00
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2024 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 "RimPlotAxisTools.h"
#include "RifEclipseSummaryAddress.h"
2024-05-03 09:54:34 +02:00
#include "RimPlotAxisLogRangeCalculator.h"
#include "RimPlotAxisProperties.h"
#include "RimPlotCurve.h"
#include "RimSummaryPlotAxisFormatter.h"
2024-05-03 09:54:34 +02:00
#include "RiuPlotAxis.h"
#include "RiuPlotWidget.h"
#include "RiuQwtPlotWidget.h"
#include "qwt_plot.h"
#include "qwt_scale_draw.h"
#include "qwt_text.h"
#include <cmath>
namespace RimPlotAxisTools
{
//--------------------------------------------------------------------------------------------------
// e format as [-]9.9e[+|-]999
// E format as[-]9.9E[+| -]999
// f format as[-]9.9
// g use e or f format, whichever is the most concise
// G use E or f format, whichever is the most concise
//--------------------------------------------------------------------------------------------------
class SummaryScaleDraw : public QwtScaleDraw
{
public:
SummaryScaleDraw( double scaleFactor,
int numberOfDecimals,
RimPlotAxisProperties::NumberFormatType numberFormat = RimPlotAxisProperties::NUMBER_FORMAT_AUTO )
{
m_scaleFactor = scaleFactor;
m_numberOfDecimals = numberOfDecimals;
m_numberFormat = numberFormat;
}
QwtText label( double value ) const override { return axisValueText( value, m_scaleFactor, m_numberOfDecimals, m_numberFormat ); }
private:
double m_scaleFactor;
int m_numberOfDecimals;
RimPlotAxisProperties::NumberFormatType m_numberFormat;
};
2024-05-03 09:54:34 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void updateVisibleRangesFromPlotWidget( RimPlotAxisProperties* axisProperties, RiuPlotAxis plotAxis, const RiuPlotWidget* const plotWidget )
2024-05-03 09:54:34 +02:00
{
if ( !plotWidget || !axisProperties ) return;
auto [axisRangeMin, axisRangeMax] = plotWidget->axisRange( plotAxis );
axisProperties->setVisibleRangeMin( std::min( axisRangeMin, axisRangeMax ) );
axisProperties->setVisibleRangeMax( std::max( axisRangeMin, axisRangeMax ) );
axisProperties->updateConnectedEditors();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void updatePlotWidgetFromAxisProperties( RiuPlotWidget* plotWidget,
RiuPlotAxis axis,
const RimPlotAxisProperties* const axisProperties,
const QString& axisTitle,
const std::vector<const RimPlotCurve*>& plotCurves )
2024-05-03 09:54:34 +02:00
{
if ( !plotWidget || !axisProperties ) return;
if ( axisProperties->isActive() )
{
plotWidget->enableAxis( axis, true );
Qt::AlignmentFlag alignment = Qt::AlignCenter;
if ( axisProperties->titlePosition() == RimPlotAxisPropertiesInterface::AXIS_TITLE_END )
{
alignment = Qt::AlignRight;
}
plotWidget->setAxisFontsAndAlignment( axis, axisProperties->titleFontSize(), axisProperties->valuesFontSize(), false, alignment );
if ( !axisTitle.isEmpty() )
{
plotWidget->setAxisTitleText( axis, axisTitle + RimPlotAxisTools::scaleFactorText( axisProperties ) );
2024-05-03 09:54:34 +02:00
}
plotWidget->setAxisTitleEnabled( axis, true );
applyAxisScaleDraw( plotWidget, axis, axisProperties );
2024-05-03 09:54:34 +02:00
if ( axisProperties->isLogarithmicScaleEnabled() )
{
bool isLogScale = plotWidget->axisScaleType( axis ) == RiuPlotWidget::AxisScaleType::LOGARITHMIC;
if ( !isLogScale )
{
plotWidget->setAxisScaleType( axis, RiuPlotWidget::AxisScaleType::LOGARITHMIC );
plotWidget->setAxisMaxMinor( axis, 5 );
}
double min = axisProperties->visibleRangeMin();
double max = axisProperties->visibleRangeMax();
if ( axisProperties->isAutoZoom() )
{
RimPlotAxisLogRangeCalculator logRangeCalculator( axis.axis(), plotCurves );
logRangeCalculator.computeAxisRange( &min, &max );
}
if ( axisProperties->isAxisInverted() )
{
std::swap( min, max );
}
plotWidget->setAxisScale( axis, min, max );
}
else
{
bool isLinearScale = plotWidget->axisScaleType( axis ) == RiuPlotWidget::AxisScaleType::LINEAR;
if ( !isLinearScale )
{
plotWidget->setAxisScaleType( axis, RiuPlotWidget::AxisScaleType::LINEAR );
plotWidget->setAxisMaxMinor( axis, 3 );
}
if ( axisProperties->isAutoZoom() )
{
plotWidget->setAxisAutoScale( axis, true );
plotWidget->setAxisInverted( axis, axisProperties->isAxisInverted() );
}
else
{
double min = axisProperties->visibleRangeMin();
double max = axisProperties->visibleRangeMax();
if ( axisProperties->isAxisInverted() )
{
std::swap( min, max );
}
plotWidget->setAxisScale( axis, min, max );
}
}
}
else
{
plotWidget->enableAxis( axis, false );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void applyAxisScaleDraw( RiuPlotWidget* plotWidget, RiuPlotAxis axis, const RimPlotAxisProperties* const axisProperties )
{
if ( auto qwtPlotWidget = dynamic_cast<RiuQwtPlotWidget*>( plotWidget ) )
{
auto qwtAxisId = qwtPlotWidget->toQwtPlotAxis( axis );
if ( axisProperties->numberFormat() == RimPlotAxisProperties::NUMBER_FORMAT_AUTO && axisProperties->scaleFactor() == 1.0 )
{
// Default to Qwt's own scale draw to avoid changing too much for default values
qwtPlotWidget->qwtPlot()->setAxisScaleDraw( qwtAxisId, new QwtScaleDraw );
}
else
{
qwtPlotWidget->qwtPlot()->setAxisScaleDraw( qwtAxisId,
new SummaryScaleDraw( axisProperties->scaleFactor(),
axisProperties->decimalCount(),
axisProperties->numberFormat() ) );
}
}
}
//--------------------------------------------------------------------------------------------------
/// Text for a single axis value, scaled by the given scale factor and formatted using the given number format
//--------------------------------------------------------------------------------------------------
QString axisValueText( double value, double scaleFactor, int numberOfDecimals, RimPlotAxisProperties::NumberFormatType numberFormat )
{
double displayValue = scaleFactor != 0.0 ? value / scaleFactor : value;
if ( qFuzzyCompare( displayValue + 1.0, 1.0 ) ) displayValue = 0.0;
char format = 'g';
if ( numberFormat == RimPlotAxisProperties::NUMBER_FORMAT_DECIMAL ) format = 'f';
if ( numberFormat == RimPlotAxisProperties::NUMBER_FORMAT_SCIENTIFIC ) format = 'e';
int precision = numberOfDecimals;
if ( format == 'g' )
{
// The 'g' format interprets the precision as the number of significant digits, while the user specifies the
// number of decimals. Add the number of digits in the integer part to display the requested number of decimals.
const double absValue = std::abs( displayValue );
const int integerDigits = absValue >= 1.0 ? static_cast<int>( std::floor( std::log10( absValue ) ) ) + 1 : 1;
precision = integerDigits + numberOfDecimals;
}
return QString::number( displayValue, format, precision );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString scaleFactorText( const RimPlotAxisProperties* const axisProperties )
{
if ( axisProperties->scaleFactor() != 1.0 )
{
int exponent = std::log10( axisProperties->scaleFactor() );
return QString( " x 10<sup>%1</sup> " ).arg( QString::number( exponent ) );
}
return {};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString axisTextForAddress( RifEclipseSummaryAddress address )
{
if ( address.isCalculated() )
{
auto shortName = shortCalculationName( address.uiText() );
return QString::fromStdString( shortName );
}
auto candidate = QString::fromStdString( address.vectorName() );
// Strip text starting with _ to avoid duplicate axis names
auto index = candidate.indexOf( "_" );
if ( index != -1 ) candidate = candidate.left( index );
return candidate;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::string shortCalculationName( const std::string& calculationName )
{
QString calculationShortName = QString::fromStdString( calculationName );
int indexOfFirstSpace = calculationShortName.indexOf( ' ' );
if ( indexOfFirstSpace > -1 && indexOfFirstSpace < calculationShortName.size() )
{
calculationShortName = calculationShortName.left( indexOfFirstSpace );
}
return calculationShortName.toStdString();
}
} // namespace RimPlotAxisTools