2015-09-17 18:42:35 +02:00
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015- Statoil ASA
// Copyright (C) 2015- Ceetron Solutions AS
//
// 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.
//
/////////////////////////////////////////////////////////////////////////////////
2015-11-06 08:32:58 +01:00
#include "RiuLineSegmentQwtPlotCurve.h"
2015-09-17 18:42:35 +02:00
2015-11-06 10:08:35 +01:00
#include "qwt_symbol.h"
2016-05-24 10:30:50 +02:00
#include "RigCurveDataTools.h"
#include "qwt_date.h"
2016-06-22 10:38:04 +02:00
#include "qwt_point_mapper.h"
#include "qwt_painter.h"
2015-10-15 11:27:12 +02:00
2015-09-17 18:42:35 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2015-11-06 10:08:35 +01:00
RiuLineSegmentQwtPlotCurve :: RiuLineSegmentQwtPlotCurve ( const QString & title )
: QwtPlotCurve ( title )
2015-09-17 18:42:35 +02:00
{
2016-06-22 10:38:04 +02:00
this -> setLegendAttribute ( QwtPlotCurve :: LegendShowLine , true );
this -> setLegendAttribute ( QwtPlotCurve :: LegendShowSymbol , true );
this -> setLegendAttribute ( QwtPlotCurve :: LegendShowBrush , true );
this -> setRenderHint ( QwtPlotItem :: RenderAntialiased , true );
m_symbolSkipPixelDistance = 10.0f ;
2015-09-17 18:42:35 +02:00
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2015-11-06 08:32:58 +01:00
RiuLineSegmentQwtPlotCurve ::~ RiuLineSegmentQwtPlotCurve ()
2015-09-17 18:42:35 +02:00
{
}
2016-05-24 10:30:50 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2016-10-12 13:49:57 +02:00
void RiuLineSegmentQwtPlotCurve :: setSamplesFromDateAndValues ( const std :: vector < QDateTime >& dateTimes , const std :: vector < double >& timeHistoryValues , bool removeNegativeValues )
2016-05-24 10:30:50 +02:00
{
CVF_ASSERT ( dateTimes . size () == timeHistoryValues . size ());
QPolygonF points ;
std :: vector < std :: pair < size_t , size_t > > filteredIntervals ;
{
std :: vector < double > filteredTimeHistoryValues ;
std :: vector < QDateTime > filteredDateTimes ;
{
std :: vector < std :: pair < size_t , size_t > > intervalsOfValidValues ;
2016-10-12 13:49:57 +02:00
RigCurveDataTools :: calculateIntervalsOfValidValues ( timeHistoryValues , & intervalsOfValidValues , removeNegativeValues );
2016-05-24 10:30:50 +02:00
RigCurveDataTools :: getValuesByIntervals ( timeHistoryValues , intervalsOfValidValues , & filteredTimeHistoryValues );
RigCurveDataTools :: getValuesByIntervals ( dateTimes , intervalsOfValidValues , & filteredDateTimes );
RigCurveDataTools :: computePolyLineStartStopIndices ( intervalsOfValidValues , & filteredIntervals );
}
2016-11-22 11:13:34 +01:00
for ( size_t i = 0 ; i < filteredDateTimes . size (); i ++ )
{
double milliSecSinceEpoch = QwtDate :: toDouble ( filteredDateTimes [ i ]);
points << QPointF ( milliSecSinceEpoch , filteredTimeHistoryValues [ i ]);
}
}
this -> setSamples ( points );
this -> setLineSegmentStartStopIndices ( filteredIntervals );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuLineSegmentQwtPlotCurve :: setSamplesFromTimeTAndValues ( const std :: vector < time_t >& dateTimes , const std :: vector < double >& timeHistoryValues , bool removeNegativeValues )
{
CVF_ASSERT ( dateTimes . size () == timeHistoryValues . size ());
QPolygonF points ;
std :: vector < std :: pair < size_t , size_t > > filteredIntervals ;
{
std :: vector < double > filteredTimeHistoryValues ;
std :: vector < time_t > filteredDateTimes ;
{
std :: vector < std :: pair < size_t , size_t > > intervalsOfValidValues ;
RigCurveDataTools :: calculateIntervalsOfValidValues ( timeHistoryValues , & intervalsOfValidValues , removeNegativeValues );
RigCurveDataTools :: getValuesByIntervals ( timeHistoryValues , intervalsOfValidValues , & filteredTimeHistoryValues );
RigCurveDataTools :: getValuesByIntervals ( dateTimes , intervalsOfValidValues , & filteredDateTimes );
RigCurveDataTools :: computePolyLineStartStopIndices ( intervalsOfValidValues , & filteredIntervals );
}
2016-05-24 10:30:50 +02:00
for ( size_t i = 0 ; i < filteredDateTimes . size (); i ++ )
{
2016-11-22 11:13:34 +01:00
double milliSecSinceEpoch = filteredDateTimes [ i ] * 1000 ; // This is kind of hack, as the c++ standard does not state what time_t is. "Almost always" secs since epoch according to cppreference.com
2016-05-24 10:30:50 +02:00
points << QPointF ( milliSecSinceEpoch , filteredTimeHistoryValues [ i ]);
}
}
this -> setSamples ( points );
this -> setLineSegmentStartStopIndices ( filteredIntervals );
}
2015-09-17 18:42:35 +02:00
//--------------------------------------------------------------------------------------------------
2016-11-22 11:13:34 +01:00
///
//--------------------------------------------------------------------------------------------------
void RiuLineSegmentQwtPlotCurve :: setSamplesFromTimeAndValues ( const std :: vector < double >& times , const std :: vector < double >& timeHistoryValues , bool removeNegativeValues )
{
CVF_ASSERT ( times . size () == timeHistoryValues . size ());
QPolygonF points ;
std :: vector < std :: pair < size_t , size_t > > filteredIntervals ;
{
std :: vector < double > filteredTimeHistoryValues ;
std :: vector < double > filteredTimes ;
{
std :: vector < std :: pair < size_t , size_t > > intervalsOfValidValues ;
RigCurveDataTools :: calculateIntervalsOfValidValues ( timeHistoryValues , & intervalsOfValidValues , removeNegativeValues );
RigCurveDataTools :: getValuesByIntervals ( timeHistoryValues , intervalsOfValidValues , & filteredTimeHistoryValues );
RigCurveDataTools :: getValuesByIntervals ( times , intervalsOfValidValues , & filteredTimes );
RigCurveDataTools :: computePolyLineStartStopIndices ( intervalsOfValidValues , & filteredIntervals );
}
for ( size_t i = 0 ; i < filteredTimes . size (); i ++ )
{
points << QPointF ( filteredTimes [ i ], filteredTimeHistoryValues [ i ]);
}
}
this -> setSamples ( points );
this -> setLineSegmentStartStopIndices ( filteredIntervals );
}
//--------------------------------------------------------------------------------------------------
2015-09-17 18:42:35 +02:00
///
//--------------------------------------------------------------------------------------------------
2015-11-06 08:32:58 +01:00
void RiuLineSegmentQwtPlotCurve :: drawCurve ( QPainter * p , int style ,
2015-09-17 18:42:35 +02:00
const QwtScaleMap & xMap , const QwtScaleMap & yMap ,
const QRectF & canvasRect , int from , int to ) const
{
2015-10-15 23:12:18 +02:00
size_t intervalCount = m_polyLineStartStopIndices . size ();
2015-09-17 18:42:35 +02:00
if ( intervalCount > 0 )
{
for ( size_t intIdx = 0 ; intIdx < intervalCount ; intIdx ++ )
{
2015-11-06 10:08:35 +01:00
if ( m_polyLineStartStopIndices [ intIdx ]. first == m_polyLineStartStopIndices [ intIdx ]. second )
{
// Use a symbol to draw a single value, as a single value will not be visible
// when using QwtPlotCurve::drawCurve without symbols activated
QwtSymbol symbol ( QwtSymbol :: XCross );
symbol . setSize ( 10 , 10 );
QwtPlotCurve :: drawSymbols ( p , symbol , xMap , yMap , canvasRect , ( int ) m_polyLineStartStopIndices [ intIdx ]. first , ( int ) m_polyLineStartStopIndices [ intIdx ]. second );
}
else
{
QwtPlotCurve :: drawCurve ( p , style , xMap , yMap , canvasRect , ( int ) m_polyLineStartStopIndices [ intIdx ]. first , ( int ) m_polyLineStartStopIndices [ intIdx ]. second );
}
2015-09-17 18:42:35 +02:00
}
}
2015-11-06 10:08:35 +01:00
else
{
QwtPlotCurve :: drawCurve ( p , style , xMap , yMap , canvasRect , from , to );
}
2015-09-17 18:42:35 +02:00
};
2015-10-15 11:27:12 +02:00
2016-06-22 10:38:04 +02:00
//--------------------------------------------------------------------------------------------------
/// Drawing symbols but skipping if they are to close to the previous one
//--------------------------------------------------------------------------------------------------
void RiuLineSegmentQwtPlotCurve :: drawSymbols ( QPainter * painter , const QwtSymbol & symbol ,
const QwtScaleMap & xMap , const QwtScaleMap & yMap ,
const QRectF & canvasRect , int from , int to ) const
{
if ( m_symbolSkipPixelDistance <= 0 )
{
QwtPlotCurve :: drawSymbols ( painter , symbol , xMap , yMap , canvasRect , from , to );
return ;
}
QwtPointMapper mapper ;
mapper . setFlag ( QwtPointMapper :: RoundPoints ,
QwtPainter :: roundingAlignment ( painter ));
mapper . setFlag ( QwtPointMapper :: WeedOutPoints ,
testPaintAttribute ( QwtPlotCurve :: FilterPoints ));
mapper . setBoundingRect ( canvasRect );
const QPolygonF points = mapper . toPointsF ( xMap , yMap ,
data (), from , to );
int pointCount = points . size ();
QPolygonF filteredPoints ;
QPointF lastDrawnSymbolPos ;
if ( pointCount > 0 )
{
filteredPoints . push_back ( points [ 0 ]);
lastDrawnSymbolPos = points [ 0 ];
}
float sqSkipDist = m_symbolSkipPixelDistance * m_symbolSkipPixelDistance ;
for ( int pIdx = 1 ; pIdx < pointCount - 1 ; ++ pIdx )
{
QPointF diff = points [ pIdx ] - lastDrawnSymbolPos ;
float sqDistBetweenSymbols = diff . x () * diff . x () + diff . y () * diff . y ();
if ( sqDistBetweenSymbols > sqSkipDist )
{
filteredPoints . push_back ( points [ pIdx ]);
lastDrawnSymbolPos = points [ pIdx ];
}
}
if ( pointCount > 1 ) filteredPoints . push_back ( points . back ());
if ( filteredPoints . size () > 0 )
symbol . drawSymbols ( painter , filteredPoints );
}
2015-10-15 11:27:12 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2015-11-06 10:08:35 +01:00
void RiuLineSegmentQwtPlotCurve :: setLineSegmentStartStopIndices ( const std :: vector < std :: pair < size_t , size_t > >& lineSegmentStartStopIndices )
2015-11-06 08:32:58 +01:00
{
m_polyLineStartStopIndices = lineSegmentStartStopIndices ;
2015-10-15 11:27:12 +02:00
}
2016-06-22 10:38:04 +02:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuLineSegmentQwtPlotCurve :: setSymbolSkipPixelDistance ( float distance )
{
m_symbolSkipPixelDistance = distance >= 0.0f ? distance : 0.0f ;
}