ResInsight/ApplicationCode/ProjectDataModel/Summary/RimSummaryPlot.cpp

2287 lines
79 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 "RimSummaryPlot.h"
#include "RiaApplication.h"
#include "RiaFieldHandleTools.h"
#include "RiaSummaryCurveAnalyzer.h"
#include "RiaTimeHistoryCurveResampler.h"
#include "SummaryPlotCommands/RicSummaryCurveCreator.h"
#include "PlotTemplates/RimPlotTemplateFileItem.h"
#include "PlotTemplates/RimPlotTemplateFolderItem.h"
#include "RimAsciiDataCurve.h"
#include "RimEnsembleCurveSet.h"
#include "RimEnsembleCurveSetCollection.h"
#include "RimGridTimeHistoryCurve.h"
#include "RimPlotAxisProperties.h"
#include "RimProject.h"
#include "RimSummaryCase.h"
#include "RimSummaryCurve.h"
#include "RimSummaryCurveCollection.h"
#include "RimSummaryCurveFilter.h"
#include "RimSummaryCurvesCalculator.h"
#include "RimSummaryPlotCollection.h"
#include "RimSummaryPlotNameHelper.h"
#include "RimSummaryTimeAxisProperties.h"
#include "RimSummaryPlotFilterTextCurveSetEditor.h"
#include "RiuPlotMainWindowTools.h"
#include "RiuSummaryQwtPlot.h"
#include "cvfColor3.h"
#include "cafPdmUiCheckBoxEditor.h"
#include "cafPdmUiTreeOrdering.h"
#include "qwt_abstract_legend.h"
#include "qwt_legend.h"
#include "qwt_plot_curve.h"
#include "qwt_plot_renderer.h"
#include "qwt_plot_textlabel.h"
#include "qwt_scale_engine.h"
#include <QDateTime>
#include <QRectF>
#include <QString>
#include "RiaColorTables.h"
#include "RiaSummaryCurveDefinition.h"
#include <QDebug>
#include <limits>
#include <set>
CAF_PDM_SOURCE_INIT( RimSummaryPlot, "SummaryPlot" );
//--------------------------------------------------------------------------------------------------
/// Internal types
//--------------------------------------------------------------------------------------------------
enum class ResampleAlgorithm
{
NONE,
DATA_DECIDES,
PERIOD_END
};
struct CurveData
{
QString name;
RifEclipseSummaryAddress address;
std::vector<double> values;
};
class CurvesData
{
public:
CurvesData()
: resamplePeriod( DateTimePeriod::NONE )
{
}
void clear()
{
resamplePeriod = DateTimePeriod::NONE;
caseNames.clear();
timeSteps.clear();
allCurveData.clear();
}
DateTimePeriod resamplePeriod;
std::vector<QString> caseNames;
std::vector<std::vector<time_t>> timeSteps;
std::vector<std::vector<CurveData>> allCurveData;
};
//--------------------------------------------------------------------------------------------------
/// Internal functions
//--------------------------------------------------------------------------------------------------
enum SummaryCurveType
{
CURVE_TYPE_GRID = 0x1,
CURVE_TYPE_OBSERVED = 0x2
};
void populateSummaryCurvesData( std::vector<RimSummaryCurve*> curves, SummaryCurveType curveType, CurvesData* curvesData );
void populateTimeHistoryCurvesData( std::vector<RimGridTimeHistoryCurve*> curves, CurvesData* curvesData );
void populateAsciiDataCurvesData( std::vector<RimAsciiDataCurve*> curves, CurvesData* curvesData );
void prepareCaseCurvesForExport( DateTimePeriod period,
ResampleAlgorithm algorithm,
const CurvesData& inputCurvesData,
CurvesData* resultCurvesData );
void appendToExportDataForCase( QString& out,
const std::vector<time_t>& timeSteps,
const std::vector<CurveData>& curveData );
void appendToExportData( QString& out, const std::vector<CurvesData>& curvesData );
CurvesData concatCurvesData( const std::vector<CurvesData>& curvesData );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimSummaryPlot::RimSummaryPlot()
{
CAF_PDM_InitObject( "Summary Plot", ":/SummaryPlotLight16x16.png", "", "" );
CAF_PDM_InitField( &m_userDefinedPlotTitle, "PlotDescription", QString( "Summary Plot" ), "Title", "", "", "" );
CAF_PDM_InitField( &m_showPlotTitle, "ShowPlotTitle", true, "Plot Title", "", "", "" );
m_showPlotTitle.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN );
CAF_PDM_InitField( &m_showLegend, "ShowLegend", true, "Legend", "", "", "" );
m_showLegend.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN );
CAF_PDM_InitField( &m_legendFontSize, "LegendFontSize", 11, "Legend Font Size", "", "", "" );
m_showLegend.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN );
CAF_PDM_InitField( &m_useAutoPlotTitle, "IsUsingAutoName", true, "Auto Title", "", "", "" );
m_useAutoPlotTitle.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN );
CAF_PDM_InitField( &m_normalizeCurveYValues, "normalizeCurveYValues", false, "Normalize all curves", "", "", "" );
m_normalizeCurveYValues.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN );
CAF_PDM_InitFieldNoDefault( &m_curveFilters_OBSOLETE, "SummaryCurveFilters", "", "", "", "" );
m_curveFilters_OBSOLETE.uiCapability()->setUiTreeHidden( true );
CAF_PDM_InitFieldNoDefault( &m_summaryCurveCollection, "SummaryCurveCollection", "", "", "", "" );
m_summaryCurveCollection.uiCapability()->setUiTreeHidden( true );
m_summaryCurveCollection = new RimSummaryCurveCollection;
CAF_PDM_InitFieldNoDefault( &m_ensembleCurveSetCollection, "EnsembleCurveSetCollection", "", "", "", "" );
m_ensembleCurveSetCollection.uiCapability()->setUiTreeHidden( true );
m_ensembleCurveSetCollection.uiCapability()->setUiHidden( true );
m_ensembleCurveSetCollection = new RimEnsembleCurveSetCollection();
CAF_PDM_InitFieldNoDefault( &m_summaryCurves_OBSOLETE, "SummaryCurves", "", "", "", "" );
m_summaryCurves_OBSOLETE.uiCapability()->setUiTreeHidden( true );
CAF_PDM_InitFieldNoDefault( &m_gridTimeHistoryCurves, "GridTimeHistoryCurves", "", "", "", "" );
m_gridTimeHistoryCurves.uiCapability()->setUiTreeHidden( true );
CAF_PDM_InitFieldNoDefault( &m_asciiDataCurves, "AsciiDataCurves", "", "", "", "" );
m_asciiDataCurves.uiCapability()->setUiTreeHidden( true );
CAF_PDM_InitFieldNoDefault( &m_leftYAxisProperties, "LeftYAxisProperties", "Left Y Axis", "", "", "" );
m_leftYAxisProperties.uiCapability()->setUiTreeHidden( true );
m_leftYAxisProperties = new RimPlotAxisProperties;
m_leftYAxisProperties->setNameAndAxis( "Left Y-Axis", QwtPlot::yLeft );
CAF_PDM_InitFieldNoDefault( &m_rightYAxisProperties, "RightYAxisProperties", "Right Y Axis", "", "", "" );
m_rightYAxisProperties.uiCapability()->setUiTreeHidden( true );
m_rightYAxisProperties = new RimPlotAxisProperties;
m_rightYAxisProperties->setNameAndAxis( "Right Y-Axis", QwtPlot::yRight );
CAF_PDM_InitFieldNoDefault( &m_bottomAxisProperties, "BottomAxisProperties", "Bottom X Axis", "", "", "" );
m_bottomAxisProperties.uiCapability()->setUiTreeHidden( true );
m_bottomAxisProperties = new RimPlotAxisProperties;
m_bottomAxisProperties->setNameAndAxis( "Bottom X-Axis", QwtPlot::xBottom );
CAF_PDM_InitFieldNoDefault( &m_timeAxisProperties, "TimeAxisProperties", "Time Axis", "", "", "" );
m_timeAxisProperties.uiCapability()->setUiTreeHidden( true );
m_timeAxisProperties = new RimSummaryTimeAxisProperties;
CAF_PDM_InitField( &m_isAutoZoom_OBSOLETE, "AutoZoom", true, "Auto Zoom", "", "", "" );
RiaFieldhandleTools::disableWriteAndSetFieldHidden( &m_isAutoZoom_OBSOLETE );
CAF_PDM_InitFieldNoDefault( &m_plotTemplate, "PlotTemplate", "Template", "", "", "" );
CAF_PDM_InitFieldNoDefault( &m_textCurveSetEditor, "SummaryPlotFilterTextCurveSetEditor", "Text Filter Curve Creator", "", "", "" );
m_textCurveSetEditor.uiCapability()->setUiTreeHidden( true );
m_textCurveSetEditor = new RimSummaryPlotFilterTextCurveSetEditor;
m_isCrossPlot = false;
m_nameHelperAllCurves.reset( new RimSummaryPlotNameHelper );
setPlotInfoLabel( "Filters Active" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimSummaryPlot::~RimSummaryPlot()
{
removeMdiWindowFromMdiArea();
deleteViewWidget();
m_summaryCurves_OBSOLETE.deleteAllChildObjects();
m_curveFilters_OBSOLETE.deleteAllChildObjects();
delete m_summaryCurveCollection;
delete m_ensembleCurveSetCollection;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updateAxes()
{
updateAxis( RiaDefines::PLOT_AXIS_LEFT );
updateAxis( RiaDefines::PLOT_AXIS_RIGHT );
if ( m_isCrossPlot )
{
updateBottomXAxis();
}
else
{
updateTimeAxis();
}
updateZoomInQwt();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimSummaryPlot::isLogarithmicScaleEnabled( RiaDefines::PlotAxis plotAxis ) const
{
return yAxisPropertiesLeftOrRight( plotAxis )->isLogarithmicScaleEnabled();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimSummaryTimeAxisProperties* RimSummaryPlot::timeAxisProperties()
{
return m_timeAxisProperties();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
time_t RimSummaryPlot::firstTimeStepOfFirstCurve()
{
RimSummaryCurve* firstCurve = nullptr;
if ( m_summaryCurveCollection )
{
std::vector<RimSummaryCurve*> curves = m_summaryCurveCollection->curves();
size_t i = 0;
while ( firstCurve == nullptr && i < curves.size() )
{
firstCurve = curves[i];
++i;
}
}
if ( firstCurve && firstCurve->timeStepsY().size() > 0 )
{
return firstCurve->timeStepsY()[0];
}
else
return time_t( 0 );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QWidget* RimSummaryPlot::viewWidget()
{
return m_qwtPlot;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimSummaryPlot::asciiDataForPlotExport( DateTimePeriod resamplingPeriod ) const
{
QString out;
RiaTimeHistoryCurveResampler resampler;
// Summary and time history (from grid) curves
{
std::vector<RimSummaryCurve*> curves;
this->descendantsIncludingThisOfType( curves );
CurvesData summaryCurvesGridData;
CurvesData summaryCurvesObsData;
populateSummaryCurvesData( curves, CURVE_TYPE_GRID, &summaryCurvesGridData );
populateSummaryCurvesData( curves, CURVE_TYPE_OBSERVED, &summaryCurvesObsData );
CurvesData timeHistoryCurvesData;
populateTimeHistoryCurvesData( m_gridTimeHistoryCurves.childObjects(), &timeHistoryCurvesData );
// Export observed data
appendToExportData( out, {summaryCurvesObsData} );
std::vector<CurvesData> exportData( 2 );
// Summary grid data for export
prepareCaseCurvesForExport( resamplingPeriod,
ResampleAlgorithm::DATA_DECIDES,
summaryCurvesGridData,
&exportData[0] );
// Time history data for export
prepareCaseCurvesForExport( resamplingPeriod, ResampleAlgorithm::PERIOD_END, timeHistoryCurvesData, &exportData[1] );
// Export resampled summary and time history data
appendToExportData( out, exportData );
}
// Pasted observed data
{
CurvesData asciiCurvesData;
populateAsciiDataCurvesData( m_asciiDataCurves.childObjects(), &asciiCurvesData );
appendToExportData( out, {asciiCurvesData} );
}
return out;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimSummaryCurve*> RimSummaryPlot::summaryAndEnsembleCurves() const
{
std::vector<RimSummaryCurve*> curves = summaryCurves();
for ( const auto& curveSet : ensembleCurveSetCollection()->curveSets() )
{
for ( const auto& curve : curveSet->curves() )
{
curves.push_back( curve );
}
}
return curves;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<RiaSummaryCurveDefinition> RimSummaryPlot::summaryAndEnsembleCurveDefinitions() const
{
std::set<RiaSummaryCurveDefinition> allCurveDefs;
for ( const auto& curve : this->summaryAndEnsembleCurves() )
{
allCurveDefs.insert( RiaSummaryCurveDefinition( curve->summaryCaseY(), curve->summaryAddressY() ) );
}
return allCurveDefs;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimSummaryCurve*> RimSummaryPlot::summaryCurves() const
{
return m_summaryCurveCollection->curves();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::deleteAllSummaryCurves()
{
m_summaryCurveCollection->deleteAllCurves();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimSummaryCurveCollection* RimSummaryPlot::summaryCurveCollection() const
{
return m_summaryCurveCollection();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiuSummaryQwtPlot* RimSummaryPlot::qwtPlot() const
{
return m_qwtPlot;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimEnsembleCurveSet*> RimSummaryPlot::curveSets() const
{
return ensembleCurveSetCollection()->curveSets();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updatePlotTitle()
{
updateNameHelperWithCurveData( m_nameHelperAllCurves.get() );
if ( m_useAutoPlotTitle )
{
m_userDefinedPlotTitle = m_nameHelperAllCurves->plotTitle();
}
updateCurveNames();
updateMdiWindowTitle();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const RimSummaryPlotNameHelper* RimSummaryPlot::activePlotTitleHelperAllCurves() const
{
if ( m_useAutoPlotTitle() )
{
return m_nameHelperAllCurves.get();
}
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimSummaryPlot::generatedPlotTitleFromAllCurves() const
{
RimSummaryPlotNameHelper nameHelper;
updateNameHelperWithCurveData( &nameHelper );
return nameHelper.plotTitle();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::copyAxisPropertiesFromOther( const RimSummaryPlot& sourceSummaryPlot )
{
{
QString data = sourceSummaryPlot.yAxisPropertiesLeftOrRight( RiaDefines::PLOT_AXIS_LEFT )->writeObjectToXmlString();
yAxisPropertiesLeftOrRight( RiaDefines::PLOT_AXIS_LEFT )
->readObjectFromXmlString( data, caf::PdmDefaultObjectFactory::instance() );
}
{
QString data = sourceSummaryPlot.yAxisPropertiesLeftOrRight( RiaDefines::PLOT_AXIS_RIGHT )->writeObjectToXmlString();
yAxisPropertiesLeftOrRight( RiaDefines::PLOT_AXIS_RIGHT )
->readObjectFromXmlString( data, caf::PdmDefaultObjectFactory::instance() );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updateAll()
{
if ( qwtPlot() )
{
updatePlotTitle();
qwtPlot()->updateLegend();
updateAxes();
updateZoomInQwt();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updateAllLegendItems()
{
reattachAllCurves();
if ( qwtPlot() )
{
qwtPlot()->updateLegend();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::setPlotInfoLabel( const QString& label )
{
auto qwtText = QwtText( label );
qwtText.setRenderFlags( Qt::AlignBottom | Qt::AlignRight );
QFont font;
font.setBold( true );
qwtText.setFont( font );
m_plotInfoLabel.reset( new QwtPlotTextLabel() );
m_plotInfoLabel->setText( qwtText );
m_plotInfoLabel->setMargin( 10 );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::showPlotInfoLabel( bool show )
{
if ( show )
m_plotInfoLabel->attach( m_qwtPlot );
else
m_plotInfoLabel->detach();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updatePlotInfoLabel()
{
bool anyCurveSetFiltered = false;
for ( auto group : m_ensembleCurveSetCollection->curveSets() )
{
if ( group->isFiltered() )
{
anyCurveSetFiltered = true;
break;
}
}
showPlotInfoLabel( anyCurveSetFiltered );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimSummaryPlot::containsResamplableCurves() const
{
std::vector<RimSummaryCurve*> summaryCurves = summaryAndEnsembleCurves();
size_t resamplableSummaryCurveCount = std::count_if( summaryCurves.begin(),
summaryCurves.end(),
[]( RimSummaryCurve* curve ) {
return curve->summaryCaseY()
? !curve->summaryCaseY()->isObservedData()
: false;
} );
return !m_gridTimeHistoryCurves.empty() || resamplableSummaryCurveCount > 0;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t RimSummaryPlot::singleColorCurveCount() const
{
auto allCurveSets = ensembleCurveSetCollection()->curveSets();
size_t colorIndex = std::count_if( allCurveSets.begin(), allCurveSets.end(), []( RimEnsembleCurveSet* curveSet ) {
return curveSet->colorMode() == RimEnsembleCurveSet::SINGLE_COLOR;
} );
colorIndex += curveCount();
return colorIndex;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::applyDefaultCurveAppearances()
{
std::set<RiaSummaryCurveDefinition> allCurveDefs = this->summaryAndEnsembleCurveDefinitions();
RimSummaryCurveAppearanceCalculator curveLookCalc( allCurveDefs );
// Summary curves
for ( auto& curve : this->summaryCurves() )
{
curve->resetAppearance();
curveLookCalc.setupCurveLook( curve );
}
// Ensemble curve sets
int colorIndex = 0;
for ( auto& curveSet : this->ensembleCurveSetCollection()->curveSets() )
{
if ( curveSet->colorMode() != RimEnsembleCurveSet::SINGLE_COLOR ) continue;
curveSet->setColor( RiaColorTables::summaryCurveDefaultPaletteColors().cycledColor3f( colorIndex++ ) );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimSummaryPlot::hasCustomFontSizes( RiaDefines::FontSettingType fontSettingType, int defaultFontSize ) const
{
if ( fontSettingType != RiaDefines::PLOT_FONT ) return false;
for ( auto plotAxis : allPlotAxes() )
{
if ( plotAxis->titleFontSize() != defaultFontSize || plotAxis->valuesFontSize() != defaultFontSize )
{
return true;
}
}
if ( m_legendFontSize() != defaultFontSize )
{
return true;
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimSummaryPlot::applyFontSize( RiaDefines::FontSettingType fontSettingType,
int oldFontSize,
int fontSize,
bool forceChange /*= false*/ )
{
if ( fontSettingType != RiaDefines::PLOT_FONT ) return false;
bool anyChange = false;
for ( auto plotAxis : allPlotAxes() )
{
if ( forceChange || plotAxis->titleFontSize() == oldFontSize )
{
plotAxis->setTitleFontSize( fontSize );
anyChange = true;
}
if ( forceChange || plotAxis->valuesFontSize() == oldFontSize )
{
plotAxis->setValuesFontSize( fontSize );
anyChange = true;
}
}
if ( forceChange || m_legendFontSize() == oldFontSize )
{
m_legendFontSize = fontSize;
anyChange = true;
}
if ( anyChange ) loadDataAndUpdate();
return anyChange;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::setNormalizationEnabled( bool enable )
{
m_normalizeCurveYValues = enable;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimSummaryPlot::isNormalizationEnabled()
{
return m_normalizeCurveYValues();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updateAxisScaling()
{
loadDataAndUpdate();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updateAxisDisplay()
{
updateAxes();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updateAxis( RiaDefines::PlotAxis plotAxis )
{
if ( !m_qwtPlot ) return;
QwtPlot::Axis qwtAxis = QwtPlot::yLeft;
if ( plotAxis == RiaDefines::PLOT_AXIS_LEFT )
{
qwtAxis = QwtPlot::yLeft;
}
else
{
qwtAxis = QwtPlot::yRight;
}
RimPlotAxisProperties* yAxisProperties = yAxisPropertiesLeftOrRight( plotAxis );
if ( yAxisProperties->isActive() && hasVisibleCurvesForAxis( plotAxis ) )
{
m_qwtPlot->enableAxis( qwtAxis, true );
std::set<QString> timeHistoryQuantities;
for ( auto c : visibleTimeHistoryCurvesForAxis( plotAxis ) )
{
timeHistoryQuantities.insert( c->quantityName() );
}
RimSummaryPlotYAxisFormatter calc( yAxisProperties,
visibleSummaryCurvesForAxis( plotAxis ),
visibleAsciiDataCurvesForAxis( plotAxis ),
timeHistoryQuantities );
calc.applyYAxisPropertiesToPlot( m_qwtPlot );
}
else
{
m_qwtPlot->enableAxis( qwtAxis, false );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updateZoomForAxis( RiaDefines::PlotAxis plotAxis )
{
if ( plotAxis == RiaDefines::PLOT_AXIS_BOTTOM )
{
if ( m_isCrossPlot )
{
if ( m_bottomAxisProperties->isAutoZoom() )
{
m_qwtPlot->setAxisAutoScale( QwtPlot::xBottom, true );
}
else
{
m_qwtPlot->setAxisScale( QwtPlot::xBottom,
m_bottomAxisProperties->visibleRangeMin(),
m_bottomAxisProperties->visibleRangeMax() );
}
}
else
{
if ( m_timeAxisProperties->isAutoZoom() )
{
m_qwtPlot->setAxisAutoScale( QwtPlot::xBottom, true );
}
else
{
m_qwtPlot->setAxisScale( QwtPlot::xBottom,
m_timeAxisProperties->visibleRangeMin(),
m_timeAxisProperties->visibleRangeMax() );
}
}
}
else
{
RimPlotAxisProperties* yAxisProps = yAxisPropertiesLeftOrRight( plotAxis );
if ( yAxisProps->isAutoZoom() )
{
if ( yAxisProps->isLogarithmicScaleEnabled )
{
std::vector<const QwtPlotCurve*> plotCurves;
for ( RimSummaryCurve* c : visibleSummaryCurvesForAxis( plotAxis ) )
{
plotCurves.push_back( c->qwtPlotCurve() );
}
for ( RimGridTimeHistoryCurve* c : visibleTimeHistoryCurvesForAxis( plotAxis ) )
{
plotCurves.push_back( c->qwtPlotCurve() );
}
for ( RimAsciiDataCurve* c : visibleAsciiDataCurvesForAxis( plotAxis ) )
{
plotCurves.push_back( c->qwtPlotCurve() );
}
double min, max;
RimPlotAxisLogRangeCalculator calc( QwtPlot::yLeft, plotCurves );
calc.computeAxisRange( &min, &max );
if ( yAxisProps->isAxisInverted() )
{
std::swap( min, max );
}
m_qwtPlot->setAxisScale( yAxisProps->qwtPlotAxisType(), min, max );
}
else
{
m_qwtPlot->setAxisAutoScale( yAxisProps->qwtPlotAxisType(), true );
}
}
else
{
m_qwtPlot->setAxisScale( yAxisProps->qwtPlotAxisType(),
yAxisProps->visibleRangeMin(),
yAxisProps->visibleRangeMax() );
}
m_qwtPlot->axisScaleEngine( yAxisProps->qwtPlotAxisType() )
->setAttribute( QwtScaleEngine::Inverted, yAxisProps->isAxisInverted() );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimSummaryCurve*> RimSummaryPlot::visibleSummaryCurvesForAxis( RiaDefines::PlotAxis plotAxis ) const
{
std::vector<RimSummaryCurve*> curves;
if ( plotAxis == RiaDefines::PLOT_AXIS_BOTTOM )
{
if ( m_summaryCurveCollection && m_summaryCurveCollection->isCurvesVisible() )
{
for ( RimSummaryCurve* curve : m_summaryCurveCollection->curves() )
{
if ( curve->isCurveVisible() )
{
curves.push_back( curve );
}
}
}
}
else
{
if ( m_summaryCurveCollection && m_summaryCurveCollection->isCurvesVisible() )
{
for ( RimSummaryCurve* curve : m_summaryCurveCollection->curves() )
{
if ( curve->isCurveVisible() && curve->axisY() == plotAxis )
{
curves.push_back( curve );
}
}
}
if ( m_ensembleCurveSetCollection && m_ensembleCurveSetCollection->isCurveSetsVisible() )
{
for ( RimEnsembleCurveSet* curveSet : m_ensembleCurveSetCollection->curveSets() )
{
for ( RimSummaryCurve* curve : curveSet->curves() )
{
if ( curve->isCurveVisible() && curve->axisY() == plotAxis )
{
curves.push_back( curve );
}
}
}
}
}
return curves;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimSummaryPlot::hasVisibleCurvesForAxis( RiaDefines::PlotAxis plotAxis ) const
{
if ( visibleSummaryCurvesForAxis( plotAxis ).size() > 0 )
{
return true;
}
if ( visibleTimeHistoryCurvesForAxis( plotAxis ).size() > 0 )
{
return true;
}
if ( visibleAsciiDataCurvesForAxis( plotAxis ).size() > 0 )
{
return true;
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimPlotAxisProperties* RimSummaryPlot::yAxisPropertiesLeftOrRight( RiaDefines::PlotAxis leftOrRightPlotAxis ) const
{
RimPlotAxisProperties* yAxisProps = nullptr;
if ( leftOrRightPlotAxis == RiaDefines::PLOT_AXIS_LEFT )
{
yAxisProps = m_leftYAxisProperties();
}
else
{
yAxisProps = m_rightYAxisProperties();
}
CVF_ASSERT( yAxisProps );
return yAxisProps;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimGridTimeHistoryCurve*> RimSummaryPlot::visibleTimeHistoryCurvesForAxis( RiaDefines::PlotAxis plotAxis ) const
{
std::vector<RimGridTimeHistoryCurve*> curves;
for ( auto c : m_gridTimeHistoryCurves )
{
if ( c->isCurveVisible() )
{
if ( c->yAxis() == plotAxis || plotAxis == RiaDefines::PLOT_AXIS_BOTTOM )
{
curves.push_back( c );
}
}
}
return curves;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimAsciiDataCurve*> RimSummaryPlot::visibleAsciiDataCurvesForAxis( RiaDefines::PlotAxis plotAxis ) const
{
std::vector<RimAsciiDataCurve*> curves;
for ( auto c : m_asciiDataCurves )
{
if ( c->isCurveVisible() )
{
if ( c->yAxis() == plotAxis || plotAxis == RiaDefines::PLOT_AXIS_BOTTOM )
{
curves.push_back( c );
}
}
}
return curves;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updateTimeAxis()
{
if ( !m_qwtPlot ) return;
if ( !m_timeAxisProperties->isActive() )
{
m_qwtPlot->enableAxis( QwtPlot::xBottom, false );
return;
}
if ( m_timeAxisProperties->timeMode() == RimSummaryTimeAxisProperties::DATE )
{
RiaQDateTimeTools::DateFormatComponents dateComponents = m_timeAxisProperties->dateComponents();
RiaQDateTimeTools::TimeFormatComponents timeComponents = m_timeAxisProperties->timeComponents();
QString dateFormat = m_timeAxisProperties->dateFormat();
QString timeFormat = m_timeAxisProperties->timeFormat();
m_qwtPlot->useDateBasedTimeAxis( dateFormat, timeFormat, dateComponents, timeComponents );
}
else
{
m_qwtPlot->useTimeBasedTimeAxis();
}
m_qwtPlot->enableAxis( QwtPlot::xBottom, true );
{
QString axisTitle;
if ( m_timeAxisProperties->showTitle ) axisTitle = m_timeAxisProperties->title();
QwtText timeAxisTitle = m_qwtPlot->axisTitle( QwtPlot::xBottom );
QFont font = timeAxisTitle.font();
font.setBold( true );
font.setPointSize( m_timeAxisProperties->titleFontSize() );
timeAxisTitle.setFont( font );
timeAxisTitle.setText( axisTitle );
switch ( m_timeAxisProperties->titlePosition() )
{
case RimSummaryTimeAxisProperties::AXIS_TITLE_CENTER:
timeAxisTitle.setRenderFlags( Qt::AlignCenter );
break;
case RimSummaryTimeAxisProperties::AXIS_TITLE_END:
timeAxisTitle.setRenderFlags( Qt::AlignRight );
break;
}
m_qwtPlot->setAxisTitle( QwtPlot::xBottom, timeAxisTitle );
}
{
QFont timeAxisFont = m_qwtPlot->axisFont( QwtPlot::xBottom );
timeAxisFont.setBold( false );
timeAxisFont.setPointSize( m_timeAxisProperties->valuesFontSize() );
m_qwtPlot->setAxisFont( QwtPlot::xBottom, timeAxisFont );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updateBottomXAxis()
{
if ( !m_qwtPlot ) return;
QwtPlot::Axis qwtAxis = QwtPlot::xBottom;
RimPlotAxisProperties* bottomAxisProperties = m_bottomAxisProperties();
if ( bottomAxisProperties->isActive() )
{
m_qwtPlot->enableAxis( qwtAxis, true );
std::set<QString> timeHistoryQuantities;
RimSummaryPlotYAxisFormatter calc( bottomAxisProperties,
visibleSummaryCurvesForAxis( RiaDefines::PLOT_AXIS_BOTTOM ),
visibleAsciiDataCurvesForAxis( RiaDefines::PLOT_AXIS_BOTTOM ),
timeHistoryQuantities );
calc.applyYAxisPropertiesToPlot( m_qwtPlot );
}
else
{
m_qwtPlot->enableAxis( qwtAxis, false );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updateCaseNameHasChanged()
{
if ( m_summaryCurveCollection )
{
m_summaryCurveCollection->updateCaseNameHasChanged();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::zoomAll()
{
setAutoZoomForAllAxes( true );
updateZoomInQwt();
updateAxisRangesFromQwt();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::addCurveAndUpdate( RimSummaryCurve* curve )
{
if ( curve )
{
m_summaryCurveCollection->addCurve( curve );
if ( m_qwtPlot )
{
curve->setParentQwtPlotAndReplot( m_qwtPlot );
this->updateAxes();
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::addCurveNoUpdate( RimSummaryCurve* curve )
{
if ( curve )
{
m_summaryCurveCollection->addCurve( curve );
if ( m_qwtPlot )
{
curve->setParentQwtPlotNoReplot( m_qwtPlot );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::deleteCurve( RimSummaryCurve* curve )
{
deleteCurves( {curve} );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::deleteCurves( const std::vector<RimSummaryCurve*>& curves )
{
for ( const auto curve : curves )
{
if ( m_summaryCurveCollection )
{
for ( auto& c : m_summaryCurveCollection->curves() )
{
if ( c == curve )
{
m_summaryCurveCollection->deleteCurve( curve );
continue;
}
}
}
if ( m_ensembleCurveSetCollection )
{
for ( auto& curveSet : m_ensembleCurveSetCollection->curveSets() )
{
for ( auto& c : curveSet->curves() )
{
if ( c == curve )
{
curveSet->deleteCurve( curve );
if ( curveSet->curves().empty() )
{
if ( curveSet->colorMode() == RimEnsembleCurveSet::BY_ENSEMBLE_PARAM && qwtPlot() )
{
qwtPlot()->removeEnsembleCurveSetLegend( curveSet );
}
m_ensembleCurveSetCollection->deleteCurveSet( curveSet );
}
continue;
}
}
}
}
}
RiuPlotMainWindowTools::refreshToolbars();
updateCaseNameHasChanged();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::deleteCurvesAssosiatedWithCase( RimSummaryCase* summaryCase )
{
if ( m_summaryCurveCollection )
{
m_summaryCurveCollection->deleteCurvesAssosiatedWithCase( summaryCase );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimEnsembleCurveSetCollection* RimSummaryPlot::ensembleCurveSetCollection() const
{
return m_ensembleCurveSetCollection;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::addGridTimeHistoryCurve( RimGridTimeHistoryCurve* curve )
{
CVF_ASSERT( curve );
m_gridTimeHistoryCurves.push_back( curve );
if ( m_qwtPlot )
{
curve->setParentQwtPlotAndReplot( m_qwtPlot );
this->updateAxes();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::addGridTimeHistoryCurveNoUpdate(RimGridTimeHistoryCurve* curve)
{
CVF_ASSERT( curve );
m_gridTimeHistoryCurves.push_back( curve );
if ( m_qwtPlot )
{
curve->setParentQwtPlotNoReplot( m_qwtPlot );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimGridTimeHistoryCurve*> RimSummaryPlot::gridTimeHistoryCurves() const
{
return m_gridTimeHistoryCurves.childObjects();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::addAsciiDataCruve( RimAsciiDataCurve* curve )
{
CVF_ASSERT( curve );
m_asciiDataCurves.push_back( curve );
if ( m_qwtPlot )
{
curve->setParentQwtPlotAndReplot( m_qwtPlot );
this->updateAxes();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
caf::PdmFieldHandle* RimSummaryPlot::userDescriptionField()
{
return &m_userDefinedPlotTitle;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QList<caf::PdmOptionItemInfo> RimSummaryPlot::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions,
bool* useOptionsOnly )
{
QList<caf::PdmOptionItemInfo> options;
if ( fieldNeedingOptions == &m_legendFontSize )
{
std::vector<int> fontSizes;
fontSizes.push_back( 8 );
fontSizes.push_back( 9 );
fontSizes.push_back( 10 );
fontSizes.push_back( 11 );
fontSizes.push_back( 12 );
fontSizes.push_back( 14 );
fontSizes.push_back( 16 );
fontSizes.push_back( 18 );
fontSizes.push_back( 24 );
for ( int value : fontSizes )
{
QString text = QString( "%1" ).arg( value );
options.push_back( caf::PdmOptionItemInfo( text, value ) );
}
}
else if ( fieldNeedingOptions == &m_plotTemplate )
{
options.push_back( caf::PdmOptionItemInfo( "None", nullptr ) );
auto rootPlotTemplate = RiaApplication::instance()->project()->rootPlotTemlateItem();
if ( rootPlotTemplate )
{
std::vector<caf::PdmObject*> allTemplates;
{
RimPlotTemplateFileItem fileItem;
rootPlotTemplate->descendantsIncludingThisFromClassKeyword( fileItem.classKeyword(), allTemplates );
}
for ( auto t : allTemplates )
{
caf::PdmOptionItemInfo optionItem( t->uiName(), t );
options.push_back( optionItem );
}
}
}
return options;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::fieldChangedByUi( const caf::PdmFieldHandle* changedField,
const QVariant& oldValue,
const QVariant& newValue )
{
RimViewWindow::fieldChangedByUi( changedField, oldValue, newValue );
if ( changedField == &m_userDefinedPlotTitle || changedField == &m_showPlotTitle || changedField == &m_showLegend ||
changedField == &m_legendFontSize || changedField == &m_useAutoPlotTitle )
{
updatePlotTitle();
updateConnectedEditors();
}
if ( changedField == &m_useAutoPlotTitle && !m_useAutoPlotTitle )
{
// When auto name of plot is turned off, update the auto name for all curves
for ( auto c : summaryCurves() )
{
c->updateCurveNameNoLegendUpdate();
}
}
if ( changedField == &m_normalizeCurveYValues )
{
this->loadDataAndUpdate();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QImage RimSummaryPlot::snapshotWindowContent()
{
#if 0
// This does not work with the color legend widgets. Is there a reason for doing this, and not to grab the widget ?
QImage image;
if (m_qwtPlot)
{
image = QImage(m_qwtPlot->size(), QImage::Format_ARGB32);
image.fill(QColor(Qt::white).rgb());
QPainter painter(&image);
QRectF rect(0, 0, m_qwtPlot->size().width(), m_qwtPlot->size().height());
QwtPlotRenderer plotRenderer;
plotRenderer.render(m_qwtPlot, &painter, rect);
}
return image;
#endif
QImage image;
if ( m_qwtPlot )
{
QPixmap pix = m_qwtPlot->grab();
image = pix.toImage();
}
return image;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName /*= ""*/ )
{
if ( uiConfigName == RicSummaryCurveCreator::CONFIGURATION_NAME )
{
uiTreeOrdering.add( &m_summaryCurveCollection );
if ( !m_isCrossPlot )
{
uiTreeOrdering.add( &m_ensembleCurveSetCollection );
}
}
else
{
caf::PdmUiTreeOrdering* axisFolder = uiTreeOrdering.add( "Axes", ":/Axes16x16.png" );
if ( m_isCrossPlot )
{
axisFolder->add( &m_bottomAxisProperties );
}
else
{
axisFolder->add( &m_timeAxisProperties );
}
axisFolder->add( &m_leftYAxisProperties );
axisFolder->add( &m_rightYAxisProperties );
uiTreeOrdering.add( &m_summaryCurveCollection );
if ( !m_isCrossPlot )
{
uiTreeOrdering.add( &m_ensembleCurveSetCollection );
}
uiTreeOrdering.add( &m_gridTimeHistoryCurves );
uiTreeOrdering.add( &m_asciiDataCurves );
}
uiTreeOrdering.skipRemainingChildren( true );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::onLoadDataAndUpdate()
{
updatePlotTitle();
updateMdiWindowVisibility();
if ( m_summaryCurveCollection )
{
m_summaryCurveCollection->loadDataAndUpdate( false );
}
m_ensembleCurveSetCollection->loadDataAndUpdate( false );
for ( RimGridTimeHistoryCurve* curve : m_gridTimeHistoryCurves )
{
curve->loadDataAndUpdate( false );
}
for ( RimAsciiDataCurve* curve : m_asciiDataCurves )
{
curve->loadDataAndUpdate( false );
}
if ( m_qwtPlot ) m_qwtPlot->updateLegend();
this->updateAxes();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updateZoomInQwt()
{
if ( m_qwtPlot )
{
updateZoomForAxis( RiaDefines::PLOT_AXIS_BOTTOM );
updateZoomForAxis( RiaDefines::PLOT_AXIS_LEFT );
updateZoomForAxis( RiaDefines::PLOT_AXIS_RIGHT );
m_qwtPlot->replot();
updateAxisRangesFromQwt();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updateZoomWindowFromQwt()
{
updateAxisRangesFromQwt();
setAutoZoomForAllAxes( false );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::selectAxisInPropertyEditor( int axis )
{
RiuPlotMainWindowTools::showPlotMainWindow();
if ( axis == QwtPlot::yLeft )
{
RiuPlotMainWindowTools::selectAsCurrentItem( m_leftYAxisProperties );
}
else if ( axis == QwtPlot::yRight )
{
RiuPlotMainWindowTools::selectAsCurrentItem( m_rightYAxisProperties );
}
else if ( axis == QwtPlot::xBottom )
{
if ( m_isCrossPlot )
{
RiuPlotMainWindowTools::selectAsCurrentItem( m_bottomAxisProperties );
}
else
{
RiuPlotMainWindowTools::selectAsCurrentItem( m_timeAxisProperties );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::setAutoZoomForAllAxes( bool enableAutoZoom )
{
m_leftYAxisProperties->setAutoZoom( enableAutoZoom );
m_rightYAxisProperties->setAutoZoom( enableAutoZoom );
if ( m_isCrossPlot )
{
m_bottomAxisProperties->setAutoZoom( enableAutoZoom );
}
else
{
m_timeAxisProperties->setAutoZoom( enableAutoZoom );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updateAxisRangesFromQwt()
{
if ( !m_qwtPlot ) return;
QwtInterval leftAxis = m_qwtPlot->currentAxisRange( QwtPlot::yLeft );
QwtInterval rightAxis = m_qwtPlot->currentAxisRange( QwtPlot::yRight );
QwtInterval timeAxis = m_qwtPlot->currentAxisRange( QwtPlot::xBottom );
m_leftYAxisProperties->visibleRangeMax = leftAxis.maxValue();
m_leftYAxisProperties->visibleRangeMin = leftAxis.minValue();
m_leftYAxisProperties->updateConnectedEditors();
m_rightYAxisProperties->visibleRangeMax = rightAxis.maxValue();
m_rightYAxisProperties->visibleRangeMin = rightAxis.minValue();
m_rightYAxisProperties->updateConnectedEditors();
if ( m_isCrossPlot )
{
m_bottomAxisProperties->visibleRangeMax = timeAxis.maxValue();
m_bottomAxisProperties->visibleRangeMin = timeAxis.minValue();
m_bottomAxisProperties->updateConnectedEditors();
}
else
{
m_timeAxisProperties->setVisibleRangeMin( timeAxis.minValue() );
m_timeAxisProperties->setVisibleRangeMax( timeAxis.maxValue() );
m_timeAxisProperties->updateConnectedEditors();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<RimPlotAxisPropertiesInterface*> RimSummaryPlot::allPlotAxes() const
{
return {m_timeAxisProperties, m_bottomAxisProperties, m_leftYAxisProperties, m_rightYAxisProperties};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::deleteAllGridTimeHistoryCurves()
{
m_gridTimeHistoryCurves.deleteAllChildObjects();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::setDescription( const QString& description )
{
m_userDefinedPlotTitle = description;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimSummaryPlot::description() const
{
return m_userDefinedPlotTitle();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::enableShowPlotTitle( bool enable )
{
m_showPlotTitle = enable;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::enableAutoPlotTitle( bool enable )
{
m_useAutoPlotTitle = enable;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimSummaryPlot::autoPlotTitle() const
{
return m_useAutoPlotTitle;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::setAsCrossPlot()
{
m_isCrossPlot = true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
{
caf::PdmUiGroup* mainOptions = uiOrdering.addNewGroup("General Plot Options");
mainOptions->add( &m_showPlotTitle );
if ( m_showPlotTitle )
{
mainOptions->add(&m_useAutoPlotTitle);
mainOptions->add(&m_userDefinedPlotTitle);
}
m_userDefinedPlotTitle.uiCapability()->setUiReadOnly( m_useAutoPlotTitle );
mainOptions->add( &m_showLegend );
if ( m_showLegend() )
{
mainOptions->add( &m_legendFontSize );
}
mainOptions->add( &m_normalizeCurveYValues );
mainOptions->add( &m_plotTemplate );
if ( !m_isCrossPlot )
{
caf::PdmUiGroup* textCurveFilterGroup = uiOrdering.addNewGroup( "Text-Based Curve Creation" );
m_textCurveSetEditor->uiOrdering( uiConfigName, *textCurveFilterGroup );
}
uiOrdering.skipRemainingFields( true );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QWidget* RimSummaryPlot::createViewWidget( QWidget* mainWindowParent )
{
if ( !m_qwtPlot )
{
m_qwtPlot = new RiuSummaryQwtPlot( this, mainWindowParent );
for ( RimGridTimeHistoryCurve* curve : m_gridTimeHistoryCurves )
{
curve->setParentQwtPlotNoReplot( m_qwtPlot );
}
for ( RimAsciiDataCurve* curve : m_asciiDataCurves )
{
curve->setParentQwtPlotNoReplot( m_qwtPlot );
}
if ( m_summaryCurveCollection )
{
m_summaryCurveCollection->setParentQwtPlotAndReplot( m_qwtPlot );
}
if ( m_ensembleCurveSetCollection )
{
m_ensembleCurveSetCollection->setParentQwtPlotAndReplot( m_qwtPlot );
}
}
return m_qwtPlot;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::deleteViewWidget()
{
detachAllCurves();
if ( m_qwtPlot )
{
m_qwtPlot->deleteLater();
m_qwtPlot = nullptr;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::initAfterRead()
{
// Move summary curves from obsolete storage to the new curve collection
std::vector<RimSummaryCurve*> curvesToMove;
for ( auto& curveFilter : m_curveFilters_OBSOLETE )
{
const auto& tmpCurves = curveFilter->curves();
curvesToMove.insert( curvesToMove.end(), tmpCurves.begin(), tmpCurves.end() );
curveFilter->clearCurvesWithoutDelete();
}
m_curveFilters_OBSOLETE.clear();
curvesToMove.insert( curvesToMove.end(), m_summaryCurves_OBSOLETE.begin(), m_summaryCurves_OBSOLETE.end() );
m_summaryCurves_OBSOLETE.clear();
for ( const auto& curve : curvesToMove )
{
m_summaryCurveCollection->addCurve( curve );
}
if ( !m_isAutoZoom_OBSOLETE() )
{
setAutoZoomForAllAxes( false );
}
RimProject* proj = nullptr;
this->firstAncestorOrThisOfType( proj );
if ( proj )
{
if ( proj->isProjectFileVersionEqualOrOlderThan( "2017.0.0" ) )
{
m_useAutoPlotTitle = false;
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updateMdiWindowTitle()
{
if ( m_qwtPlot )
{
QString plotTitle = description();
m_qwtPlot->setWindowTitle( plotTitle );
if ( m_showPlotTitle )
{
m_qwtPlot->setTitle( plotTitle );
}
else
{
m_qwtPlot->setTitle( "" );
}
if ( m_showLegend )
{
// Will be released in plot destructor or when a new legend is set
QwtLegend* legend = new QwtLegend( m_qwtPlot );
auto font = legend->font();
font.setPointSize( m_legendFontSize() );
legend->setFont( font );
m_qwtPlot->insertLegend( legend, QwtPlot::BottomLegend );
}
else
{
m_qwtPlot->insertLegend( nullptr );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updateNameHelperWithCurveData( RimSummaryPlotNameHelper* nameHelper ) const
{
if ( !nameHelper ) return;
nameHelper->clear();
std::vector<RifEclipseSummaryAddress> addresses;
std::vector<RimSummaryCase*> sumCases;
std::vector<RimSummaryCaseCollection*> ensembleCases;
if ( m_summaryCurveCollection && m_summaryCurveCollection->isCurvesVisible() )
{
for ( RimSummaryCurve* curve : m_summaryCurveCollection->curves() )
{
addresses.push_back( curve->summaryAddressY() );
sumCases.push_back( curve->summaryCaseY() );
if ( curve->summaryCaseX() )
{
sumCases.push_back( curve->summaryCaseX() );
if ( curve->summaryAddressX().category() != RifEclipseSummaryAddress::SUMMARY_INVALID )
{
addresses.push_back( curve->summaryAddressX() );
}
}
}
}
for ( auto curveSet : m_ensembleCurveSetCollection->curveSets() )
{
addresses.push_back( curveSet->summaryAddress() );
ensembleCases.push_back( curveSet->summaryCaseCollection() );
}
nameHelper->clear();
nameHelper->appendAddresses( addresses );
nameHelper->setSummaryCases( sumCases );
nameHelper->setEnsembleCases( ensembleCases );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updateCurveNames()
{
if ( m_summaryCurveCollection->isCurvesVisible() )
{
for ( auto c : summaryCurves() )
{
c->updateCurveNameNoLegendUpdate();
}
}
for ( auto curveSet : m_ensembleCurveSetCollection->curveSets() )
{
curveSet->updateEnsembleLegendItem();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::detachAllCurves()
{
if ( m_summaryCurveCollection )
{
m_summaryCurveCollection->detachQwtCurves();
}
m_ensembleCurveSetCollection->detachQwtCurves();
for ( RimGridTimeHistoryCurve* curve : m_gridTimeHistoryCurves )
{
curve->detachQwtCurve();
}
for ( RimAsciiDataCurve* curve : m_asciiDataCurves )
{
curve->detachQwtCurve();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::reattachAllCurves()
{
if ( m_summaryCurveCollection )
{
m_summaryCurveCollection->reattachQwtCurves();
}
m_ensembleCurveSetCollection->reattachQwtCurves();
for ( RimGridTimeHistoryCurve* curve : m_gridTimeHistoryCurves )
{
curve->reattachQwtCurve();
}
for ( RimAsciiDataCurve* curve : m_asciiDataCurves )
{
curve->reattachQwtCurve();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
caf::PdmObject* RimSummaryPlot::findRimPlotObjectFromQwtCurve( const QwtPlotCurve* qwtCurve ) const
{
for ( RimGridTimeHistoryCurve* curve : m_gridTimeHistoryCurves )
{
if ( curve->qwtPlotCurve() == qwtCurve )
{
return curve;
}
}
for ( RimAsciiDataCurve* curve : m_asciiDataCurves )
{
if ( curve->qwtPlotCurve() == qwtCurve )
{
return curve;
}
}
if ( m_summaryCurveCollection )
{
RimSummaryCurve* foundCurve = m_summaryCurveCollection->findRimCurveFromQwtCurve( qwtCurve );
if ( foundCurve )
{
m_summaryCurveCollection->setCurrentSummaryCurve( foundCurve );
return foundCurve;
}
}
if ( m_ensembleCurveSetCollection )
{
RimEnsembleCurveSet* foundCurveSet = m_ensembleCurveSetCollection->findRimCurveSetFromQwtCurve( qwtCurve );
if ( foundCurveSet )
{
m_ensembleCurveSetCollection->setCurrentSummaryCurveSet( foundCurveSet );
return foundCurveSet;
}
}
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::showLegend( bool enable )
{
m_showLegend = enable;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::setPlotTemplate( RimPlotTemplateFileItem* plotTemplate )
{
m_plotTemplate = plotTemplate;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimPlotTemplateFileItem* RimSummaryPlot::plotTemplate() const
{
return m_plotTemplate();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t RimSummaryPlot::curveCount() const
{
return m_summaryCurveCollection->curves().size() + m_gridTimeHistoryCurves.size() + m_asciiDataCurves.size();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::defineEditorAttribute( const caf::PdmFieldHandle* field,
QString uiConfigName,
caf::PdmUiEditorAttribute* attribute )
{
if ( field == &m_showLegend || field == &m_showPlotTitle || field == &m_useAutoPlotTitle ||
field == &m_normalizeCurveYValues )
{
caf::PdmUiCheckBoxEditorAttribute* myAttr = dynamic_cast<caf::PdmUiCheckBoxEditorAttribute*>( attribute );
if ( myAttr )
{
myAttr->m_useNativeCheckBoxLabel = true;
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void populateTimeHistoryCurvesData( std::vector<RimGridTimeHistoryCurve*> curves, CurvesData* curvesData )
{
CVF_ASSERT( curvesData );
curvesData->caseNames.clear();
curvesData->timeSteps.clear();
curvesData->allCurveData.clear();
for ( RimGridTimeHistoryCurve* curve : curves )
{
if ( !curve->isCurveVisible() ) continue;
QString curveCaseName = curve->caseName();
size_t casePosInList = cvf::UNDEFINED_SIZE_T;
for ( size_t i = 0; i < curvesData->caseNames.size(); i++ )
{
if ( curveCaseName == curvesData->caseNames[i] ) casePosInList = i;
}
CurveData curveData = {curve->curveExportDescription(), RifEclipseSummaryAddress(), curve->yValues()};
if ( casePosInList == cvf::UNDEFINED_SIZE_T )
{
curvesData->caseNames.push_back( curveCaseName );
curvesData->timeSteps.push_back( curve->timeStepValues() );
curvesData->allCurveData.push_back( std::vector<CurveData>( {curveData} ) );
}
else
{
curvesData->allCurveData[casePosInList].push_back( curveData );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void populateAsciiDataCurvesData( std::vector<RimAsciiDataCurve*> curves, CurvesData* curvesData )
{
CVF_ASSERT( curvesData );
curvesData->caseNames.clear();
curvesData->timeSteps.clear();
curvesData->allCurveData.clear();
for ( RimAsciiDataCurve* curve : curves )
{
if ( !curve->isCurveVisible() ) continue;
size_t casePosInList = cvf::UNDEFINED_SIZE_T;
CurveData curveData = {curve->curveExportDescription(), RifEclipseSummaryAddress(), curve->yValues()};
if ( casePosInList == cvf::UNDEFINED_SIZE_T )
{
curvesData->caseNames.push_back( "" );
curvesData->timeSteps.push_back( curve->timeSteps() );
curvesData->allCurveData.push_back( std::vector<CurveData>( {curveData} ) );
}
else
{
curvesData->allCurveData[casePosInList].push_back( curveData );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void populateSummaryCurvesData( std::vector<RimSummaryCurve*> curves, SummaryCurveType curveType, CurvesData* curvesData )
{
CVF_ASSERT( curvesData );
curvesData->caseNames.clear();
curvesData->timeSteps.clear();
curvesData->allCurveData.clear();
for ( RimSummaryCurve* curve : curves )
{
bool isObservedCurve = curve->summaryCaseY() ? curve->summaryCaseY()->isObservedData() : false;
if ( !curve->isCurveVisible() ) continue;
if ( isObservedCurve && ( curveType & CURVE_TYPE_OBSERVED ) == 0 ) continue;
if ( !isObservedCurve && ( curveType & CURVE_TYPE_GRID ) == 0 ) continue;
QString curveCaseName = curve->summaryCaseY()->caseName();
size_t casePosInList = cvf::UNDEFINED_SIZE_T;
for ( size_t i = 0; i < curvesData->caseNames.size(); i++ )
{
if ( curveCaseName == curvesData->caseNames[i] ) casePosInList = i;
}
CurveData curveData = {curve->curveExportDescription(), curve->summaryAddressY(), curve->valuesY()};
CurveData errorCurveData;
// Error data
auto errorValues = curve->errorValuesY();
bool hasErrorData = !errorValues.empty();
if ( hasErrorData )
{
errorCurveData.name = curve->curveExportDescription( curve->errorSummaryAddressY() );
errorCurveData.address = curve->errorSummaryAddressY();
errorCurveData.values = errorValues;
}
if ( casePosInList == cvf::UNDEFINED_SIZE_T )
{
auto curveDataList = std::vector<CurveData>( {curveData} );
if ( hasErrorData ) curveDataList.push_back( errorCurveData );
curvesData->caseNames.push_back( curveCaseName );
curvesData->timeSteps.push_back( curve->timeStepsY() );
curvesData->allCurveData.push_back( curveDataList );
}
else
{
curvesData->allCurveData[casePosInList].push_back( curveData );
if ( hasErrorData ) curvesData->allCurveData[casePosInList].push_back( errorCurveData );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void prepareCaseCurvesForExport( DateTimePeriod period,
ResampleAlgorithm algorithm,
const CurvesData& inputCurvesData,
CurvesData* resultCurvesData )
{
RiaTimeHistoryCurveResampler resampler;
resultCurvesData->clear();
if ( period != DateTimePeriod::NONE )
{
// Prepare result data
resultCurvesData->resamplePeriod = period;
for ( size_t i = 0; i < inputCurvesData.caseNames.size(); i++ )
{
// Shortcuts to input data
auto& caseName = inputCurvesData.caseNames[i];
auto& caseTimeSteps = inputCurvesData.timeSteps[i];
auto& caseCurveData = inputCurvesData.allCurveData[i];
// Prepare result data
resultCurvesData->caseNames.push_back( caseName );
resultCurvesData->allCurveData.push_back( std::vector<CurveData>() );
for ( auto& curveDataItem : caseCurveData )
{
resampler.setCurveData( curveDataItem.values, caseTimeSteps );
if ( curveDataItem.address.hasAccumulatedData() || algorithm == ResampleAlgorithm::PERIOD_END )
{
resampler.resampleAndComputePeriodEndValues( period );
}
else
{
resampler.resampleAndComputeWeightedMeanValues( period );
}
auto cd = curveDataItem;
cd.values = resampler.resampledValues();
auto& currResultCurveDataList = resultCurvesData->allCurveData[i];
currResultCurveDataList.push_back( cd );
}
resultCurvesData->timeSteps.push_back( resampler.resampledTimeSteps() );
}
}
else
{
*resultCurvesData = inputCurvesData;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void appendToExportDataForCase( QString& out, const std::vector<time_t>& timeSteps, const std::vector<CurveData>& curveData )
{
for ( size_t j = 0; j < timeSteps.size(); j++ ) // time steps & data points
{
if ( j == 0 )
{
out += "Date and time";
for ( size_t k = 0; k < curveData.size(); k++ ) // curves
{
out += "\t" + ( curveData[k].name );
}
}
out += "\n";
out += QDateTime::fromTime_t( timeSteps[j] ).toUTC().toString( "yyyy-MM-dd hh:mm:ss " );
for ( size_t k = 0; k < curveData.size(); k++ ) // curves
{
QString valueText;
if ( j < curveData[k].values.size() )
{
valueText = QString::number( curveData[k].values[j], 'g', 6 );
}
out += "\t" + valueText.rightJustified( 13 );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void appendToExportData( QString& out, const std::vector<CurvesData>& curvesData )
{
CurvesData data = concatCurvesData( curvesData );
if ( data.resamplePeriod != DateTimePeriod::NONE )
{
time_t minTimeStep = std::numeric_limits<time_t>::max();
time_t maxTimeStep = 0;
for ( auto& timeSteps : data.timeSteps )
{
if ( !timeSteps.empty() )
{
if ( timeSteps.front() < minTimeStep ) minTimeStep = timeSteps.front();
if ( timeSteps.back() > maxTimeStep ) maxTimeStep = timeSteps.back();
}
}
auto allTimeSteps = RiaTimeHistoryCurveResampler::timeStepsFromTimeRange( data.resamplePeriod,
minTimeStep,
maxTimeStep );
out += "\n\n";
out += "Date and time";
for ( size_t i = 0; i < data.caseNames.size(); i++ )
{
for ( size_t j = 0; j < data.allCurveData[i].size(); j++ )
{
out += "\t" + data.allCurveData[i][j].name;
}
}
out += "\n";
std::vector<size_t> currIndexes( data.caseNames.size() );
for ( auto& i : currIndexes )
i = 0;
for ( auto timeStep : allTimeSteps )
{
QString tt = QDateTime::fromTime_t( timeStep ).toUTC().toString( "yyyy-MM-dd hh:mm:ss " );
out += QDateTime::fromTime_t( timeStep ).toUTC().toString( "yyyy-MM-dd hh:mm:ss " );
for ( size_t i = 0; i < data.caseNames.size(); i++ ) // cases
{
// Check is time step exists in curr case
size_t& currIndex = currIndexes[i];
bool timeStepExists = currIndex < data.timeSteps[i].size() && timeStep == data.timeSteps[i][currIndex];
for ( size_t j = 0; j < data.allCurveData[i].size(); j++ ) // vectors
{
QString valueText;
if ( timeStepExists )
{
valueText = QString::number( data.allCurveData[i][j].values[currIndex], 'g', 6 );
}
else
{
valueText = "NULL";
}
out += "\t" + valueText.rightJustified( 13 );
}
if ( timeStepExists && currIndex < data.timeSteps[i].size() ) currIndex++;
}
out += "\n";
}
}
else
{
for ( size_t i = 0; i < data.caseNames.size(); i++ )
{
out += "\n\n";
if ( !data.caseNames[i].isEmpty() )
{
out += "Case: " + data.caseNames[i];
out += "\n";
}
appendToExportDataForCase( out, data.timeSteps[i], data.allCurveData[i] );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
CurvesData concatCurvesData( const std::vector<CurvesData>& curvesData )
{
CVF_ASSERT( !curvesData.empty() );
DateTimePeriod period = curvesData.front().resamplePeriod;
CurvesData resultCurvesData;
resultCurvesData.resamplePeriod = period;
for ( auto curvesDataItem : curvesData )
{
if ( curvesDataItem.caseNames.empty() ) continue;
CVF_ASSERT( curvesDataItem.resamplePeriod == period );
resultCurvesData.caseNames.insert( resultCurvesData.caseNames.end(),
curvesDataItem.caseNames.begin(),
curvesDataItem.caseNames.end() );
resultCurvesData.timeSteps.insert( resultCurvesData.timeSteps.end(),
curvesDataItem.timeSteps.begin(),
curvesDataItem.timeSteps.end() );
resultCurvesData.allCurveData.insert( resultCurvesData.allCurveData.end(),
curvesDataItem.allCurveData.begin(),
curvesDataItem.allCurveData.end() );
}
return resultCurvesData;
}